Repository navigation
feat(harness): list the agents in a repo without building it - #251
Merged
khushalsonawat merged 16 commits intoNov 10, 2026
Merged
Conversation
Adds --find-agents to the authoring entrypoint, run through the shared reading helper. It writes /work/reading/agents.json in the shape the platform's AgentScanSerializer reads, plus cost.json on every return. - A plain code walk finds candidates (framework builds, langgraph.json graphs, agent.py, provider clients) and joins files into agents by their imports, without running anything. - Each agent's folder gets TH-8805's framework answer, with a build's limits, in one child process the scan's clock can stop. - A model is asked only when the walk finds nothing usable (mostly TypeScript and JavaScript repos). Its read/glob/grep tools stay inside the source, and only the paths it names, once checked, are kept. - Names, evidence and paths are built to fit the platform's rules, and the file is checked against a copy of them before it is written. - An agent at a path the platform's rule can't carry (a Next.js app/(chat)/ route, say) is left out with truncated set, and is reported as agent_path_unsupported when nothing else is found. TH-8950 Signed-off-by: khushalsonawat <khushalsonawat@gmail.com>
TH-8950 Signed-off-by: khushalsonawat <khushalsonawat@gmail.com>
#245 replaced reading_entry._secret_values with a functools.cache reader keyed by the secrets files. The scan tests already point those files at a fresh temporary path, so each test gets its own cache entry and there is nothing left to reset. TH-8950 Signed-off-by: khushalsonawat <khushalsonawat@gmail.com>
cdileep23
requested changes
Nov 10, 2026
…ts crash - Any model error now keeps the walk's rows with truncated set and exits 0; only a scan with no rows writes scan_model_error, carrying the model's own retryable flag. A retry would pay for the model again. - A fault outside any one file in the walk (run or result) now reaches the scan's crash path (scan_crashed, retryable) instead of being reported as scan_limit_reached. - Catches are narrowed to what each step expects. A file's reader faults still leave that file unread. A folder check that fails in the child sends its trace back, and the row is marked unfinished. Faults that are still absorbed (after the paid step, closing the session, tool calls) log their trace through the reading helper's MaskSecrets filter instead of the class name only. TH-8950 Signed-off-by: khushalsonawat <khushalsonawat@gmail.com>
- agent_scan imports EXIT_DONE, EXIT_RETRYABLE, limit_seconds and reading_failure from reading_entry, and EXIT_REFUSED from agent_type_check. FIND_AGENTS now sets limit_env and limit_margin_seconds, so the helper and the scan read ALK_SCAN_MAX_SECONDS at the same moment. - The find-agents stage passes idle_retries=0 itself instead of setting session.STAGE_IDLE_RETRIES for the whole process. - The walk uses framework_detection's _Work, which takes an optional limit, instead of its own copy, and bundle_author_v2's ignore list instead of a copy held equal by a test. - The walk and an AI row's description share one folder loop (_source_files) and one shadowed-name lookup (_ShadowedNames). TH-8950 Signed-off-by: khushalsonawat <khushalsonawat@gmail.com>
- An agent's subfolder counts only the agents of its own project. Adding an unrelated project with its own agent deeper in the repo no longer moves the first agent's folder, which the platform keys on. - The walk reads files outside test, example and other side folders first, then the side folders. A large tests folder sorted ahead of the agent can no longer use up the 20,000-file cap before the agent is read. TH-8950 Signed-off-by: khushalsonawat <khushalsonawat@gmail.com>
… tests plainly - The shared-folder evidence sentence no longer asks a build to name an entry, which a build job has no field for. - Test names say "the platform format", "the platform rules" and "the path rule" instead of "his". - _result's docstring describes what it does instead of pointing at plan step numbers. TH-8950 Signed-off-by: khushalsonawat <khushalsonawat@gmail.com>
The model step also runs when the walk found agents only in test or example folders, so the test is no longer named "only when nothing is found". TH-8950 Signed-off-by: khushalsonawat <khushalsonawat@gmail.com>
The catch still keeps a paid answer from becoming a retry; it now logs the masked trace like the other absorbed faults, so a fault in the cost writer can be found. TH-8950 Signed-off-by: khushalsonawat <khushalsonawat@gmail.com>
… check faults From the review round on the fixes for the first review of this PR: - One unreadable or unparsable file no longer stops the description of a model-found agent. It marks the row short (partial) and the reading goes on, as the walk goes on past an unread file. - detect_framework takes raise_faults (off for builds). The scan's folder check turns it on, so a fault inside the framework check comes back as a trace and the row is unfinished, instead of a finished unknown. Both the child's and the parent's halves are tested. - A model tool's fault keeps the worker's exception as the cause, so its logged trace shows the real error. - Tests pin the run-time read of ALK_SCAN_MAX_SECONDS and the secret mask on every scan logger. The log comment says only the platform's secret values are masked. TH-8950 Signed-off-by: khushalsonawat <khushalsonawat@gmail.com>
…es with own code From the review round on the fixes for the first review of this PR: - The file cap is 200,000, up from 20,000. Measured: 100,000 tiny source files walk in 13 s at 266 MB, so the byte cap and the clock are what bound the walk. A repo whose own code passes 20,000 files no longer stops before its agent is read. - A folder's settings template (.env.example and its kin) is read in its folder's pass, not with the side files, so a big tests folder can't keep it from being read. - A reader fault of an unforeseen kind logs its trace once; the rest are counted (reader_faults in the walk's summary line). - ALK_SCAN_AI_MAX_SECONDS is read when the scan starts, as the clock is. - Tests: every file is read in exactly one pass; tests no longer depend on an exported ALK_SCAN_MAX_SECONDS; the process-wide idle-retry setting is set through monkeypatch. TH-8950 Signed-off-by: khushalsonawat <khushalsonawat@gmail.com>
From the last review round on the fixes for the first review of this PR: - A file over 1 MiB in a model-found agent's folder now marks the row short (partial) instead of being skipped silently, so a paid row with a missing file is never reported complete. - The description logs one trace for a reader fault of an unforeseen kind, then counts the rest, as the walk does. - Comments say traces are logged with the platform's secret values masked, not that they are fully masked. TH-8950 Signed-off-by: khushalsonawat <khushalsonawat@gmail.com>
… sandbox From the last review round on the fixes for the first review of this PR: - The file cap is 40,000, not 200,000. What the walk holds grows with the names each file imports, not its bytes: about 33 KB a file for files that each import 200 names, a 1,389 MB peak at 40,000 such files. At 200,000 such files the sandbox would kill the scan. 40,000 still covers a repo whose own code passes 20,000 files. - The partial-row sentence says files couldn't be read, not that they weren't read in time, since a file that fails to parse also sets it. - A test pins that ALK_SCAN_AI_MAX_SECONDS is read when the model step is asked, and the comment says so. TH-8950 Signed-off-by: khushalsonawat <khushalsonawat@gmail.com>
cdileep23
requested changes
Nov 10, 2026
Member
Author
|
Since your approval at 4eb45c6 there are five commits, listed in the body under "Changes since the 10 Nov approval". The two that change behaviour beyond your comments: |
The step that joins the walk's files into agents (the import search from each candidate, and the per-agent loops) now checks a deadline: the walk's own deadline plus 120 s, well inside the helper's 600 s margin before the hard stop. Past it the walk ends as stopped by the clock, so the scan writes its own file (scan_timed_out, exit 0) instead of being ended by the hard stop. The two-pass test now pins the order it claims: a settings template in a folder that sorts after tests/ is read before tests/test_a.py. TH-8950 Signed-off-by: khushalsonawat <khushalsonawat@gmail.com>
TH-8950 Signed-off-by: khushalsonawat <khushalsonawat@gmail.com>
cdileep23
approved these changes
Nov 10, 2026
Candidates that reach each other hold one entry per pair, which grows with the square of the candidates. The join now counts them as it builds them and, past 5,000,000 (about 90 MB), ends as the walk's other caps do (stopped="limit", scan_limit_reached), instead of growing until the clock stops it. TH-8950 Signed-off-by: khushalsonawat <khushalsonawat@gmail.com>
khushalsonawat
merged commit Nov 10, 2026
4c97485
into
feat/TH-8951-read-without-build
11 checks passed
This was referenced Nov 10, 2026
3 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #245 (TH-8951), which is stacked on #225 (TH-8804) and #224 (TH-8806). The base is
feat/TH-8951-read-without-build, so the diff shows only TH-8950. It retargets down the stack as those merge.Summary
The platform's Agents tab needs a list of the agents in a repo before anything is built, so a person can pick one to create. This PR adds
--find-agentsto the authoring command. It reads the repo at one commit (or an upload) without installing or running anything, and writes/work/reading/agents.jsonin the shapeAgentScanSerializerreads, pluscost.json. It uses #245's shared reading helper. Exit 0 means a file was written (found,noneorerror); 1 and 78 meanfailure.json.scan_walk.py) reads each file once, the repo's own code before test and example folders, and finds candidates: framework builds,langgraph.jsongraphs,agent.py, provider clients. It joins files into agents by their imports, so a side-folder script or a weaker file never swallows a stronger one. An agent's folder counts only agents of its own project.scan_folders.py) is TH-8805's answer for each agent's folder, with a build's limits. It runs in one child process that the scan's clock can stop.scan_ai.py) is the only paid part ($0.31–0.50 measured). It runs when the walk found no agent, found agents only in test or example folders, or found only a weak sign (a bare client or chat model) beside TypeScript or JavaScript, which the walk can't read; and only with 360 s left on the clock and the walk not stopped. Its read/glob/grep tools stay inside the source. Only the paths it names are kept, once checked, and nothing it writes reaches the file. If it fails, the walk's rows are still written withtruncated: true; only a scan with no rows writesscan_model_error.scan_crashed(retryable). Faults that are still absorbed log their trace through the reading helper's secret mask.scan_document.py): names, evidence sentences and paths are built to fit the serializer's rules. The file is checked against a copy of them (fixture pinned to e07d56fcd), and at most 50 agents are kept.Settings:
ALK_SCAN_MAX_SECONDS: the clock, 1,200 s;ALK_SCAN_AI_MAX_SECONDS: the model step's limit, 600 s;The sandbox needs 4,096 MB, 2 CPU and a lifetime of at least 2,400 s.
Why one PR: find, none and error is one agreed contract with the platform, and TH-8824 needs both halves. The walk alone would answer
nonefor a TypeScript-only repo. The model tools'{a,b}and**/glob support came from a measured failure on vercel/ai-chatbot (false "No file matches"), not from the spec.Ticket: TH-8950.
Known limits
scan_timed_outwith no rows, even if the walk had found some.scan_limit_reached, ortruncatedif it found agents. What it holds grows with the names each file imports (about 33 KB a file at 200 imported names, a 1,389 MB peak at 40,000 such files), so the cap keeps that inside the 4,096 MB sandbox. A budget on the names held, instead of a file count, is a follow-up.truncated: true, or getserroragent_path_unsupportedwhen nothing else is found. Next.js route folders such asapp/(chat)/hit this; listing them needs the rule to allow(and).unknown.{a,b}and**/matching in the model's tools.authoring_entrypoint.pyimportssysandshutiltwice (ruff F811), already on the base.Changes since the 10 Nov approval (
4eb45c60)45eb82ba: the cost-note catch logs its trace (your P3).884043ca: one unreadable file no longer stops an AI row's description;detect_frameworkgainsraise_faults(off for builds) so the scan sees a fault in the framework check and marks the row unfinished; a tool fault keeps its cause.6aeb4665: settings templates are read with the repo's own code; one trace per unforeseen reader fault;ALK_SCAN_AI_MAX_SECONDSread when the model step is asked; tests isolated from the environment. It also raised the file cap to 200,000, which the next round found unsafe for memory.81d16b54: a file over 1 MiB marks an AI row short instead of being skipped silently.b46311ad: the file cap is 40,000 (from 20,000 at your review), sized by memory; the partial-row sentence says files couldn't be read.b8970348: the step after the walk (joining files into agents) checks the walk's deadline plus 120 s and ends as a clock stop, so a huge import graph ends inscan_timed_outinstead of the hard stop (your P2); the two-pass test pins the template order (your P3).4dcea5c3: merge of feat(harness): read an agent without building it #245 atedb69263(no change to this PR's own diff).af8e86e5: the join counts candidate pairs and, past 5,000,000 (about 90 MB), ends with the walk's limit result (your P3 follow-up).Verification
uv run ruff checkon the changed files: clean apart from the pre-existing F811 abovetests/harness/test_scan_walk.py: 92 passedtests/harness/test_scan_folders.py: 7 passedtests/harness/test_scan_document.py: 17 passedtests/harness/test_scan_ai.py: 59 passedtests/harness/test_agent_scan.py: 63 passedtests/harness/test_authoring_entrypoint_find_agents.py: 5 passedtest_reading_entry.py61,test_agent_reading.py88,test_framework_detection.py251 passed (framework_detection._Worktakes an optional limit, so the walk reuses it;detect_frameworktakesraise_faults, off for builds, so the scan sees a fault in the check)uv run pytest -q: not runagent-learn release-proof: not touchedChecklist
agent_learning.*,agent-learn, or@future-agi/agent-learning-kit