autoforge-agent 0.4.0__tar.gz → 0.4.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- autoforge_agent-0.4.2/MANIFEST.in +10 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/PKG-INFO +2 -1
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/cli.py +6 -2
- autoforge_agent-0.4.2/autoforge/web/static/index.html +406 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/webtools.py +12 -7
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge_agent.egg-info/PKG-INFO +2 -1
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge_agent.egg-info/SOURCES.txt +16 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge_agent.egg-info/requires.txt +1 -0
- autoforge_agent-0.4.2/probes/FINDINGS.md +261 -0
- autoforge_agent-0.4.2/probes/probe_forge_latency.py +102 -0
- autoforge_agent-0.4.2/probes/probe_gateway_context_503.py +60 -0
- autoforge_agent-0.4.2/probes/probe_gateway_empty.py +83 -0
- autoforge_agent-0.4.2/probes/probe_gateway_max_tokens.py +122 -0
- autoforge_agent-0.4.2/probes/probe_gateway_models.py +134 -0
- autoforge_agent-0.4.2/probes/probe_gateway_thinking.py +134 -0
- autoforge_agent-0.4.2/probes/probe_generator_reply.py +69 -0
- autoforge_agent-0.4.2/probes/probe_model_latency.py +66 -0
- autoforge_agent-0.4.2/probes/raw_generator_reply.txt +23 -0
- autoforge_agent-0.4.2/probes/raw_generator_reply_clean.txt +16 -0
- autoforge_agent-0.4.2/pyproject.toml +38 -0
- autoforge_agent-0.4.2/tests/_terminal.py +127 -0
- autoforge_agent-0.4.2/tests/conftest.py +36 -0
- autoforge_agent-0.4.2/tests/mcp_server_fixture.py +176 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_setup.py +15 -0
- autoforge_agent-0.4.0/pyproject.toml +0 -24
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/README.md +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/__init__.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/__main__.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/agent.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/autonomy/__init__.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/autonomy/confirm.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/autonomy/policy.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/autonomy/roles.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/autonomy/selfmod.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/autonomy/spawn.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/autonomy/topology.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/browser.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/configfile.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/core/__init__.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/core/agent.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/core/compaction.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/core/lineedit.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/core/llm.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/core/message.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/core/steering.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/cpu/__init__.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/cpu/kernel.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/cpu/ops.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/cpu/probe.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/cpu/safety.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/cpu/tune.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/ecosystem.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/forge/__init__.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/forge/adversary.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/forge/evolution.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/forge/fuzzer.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/forge/generator.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/forge/invariance.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/forge/metacog.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/forge/pipeline.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/forge/sandbox.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/forge/validity.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/forge/verifier.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/gpu/__init__.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/gpu/backend_triton.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/gpu/bench.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/gpu/kernel.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/gpu/ops.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/gpu/probe.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/gpu/safety.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/gpu/units.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/mcp.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/measure.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/modes.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/notify.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/route/__init__.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/route/router.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/schedule.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/setup_wizard.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/skills.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/store.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/timing.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/tools/__init__.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/tools/composition.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/tools/registry.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/tools/spec.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/vision.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/web/__init__.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge/web/server.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge_agent.egg-info/dependency_links.txt +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge_agent.egg-info/entry_points.txt +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/autoforge_agent.egg-info/top_level.txt +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/setup.cfg +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_autoforge.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_browser.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_cli.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_compaction.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_compaction_wiring.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_cpu.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_ecosystem.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_execution_samples.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_forge_failure_feedback.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_generator_coercion.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_host_facts.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_invariance.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_json_repair.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_lineedit.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_live_progress.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_llm_client.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_llm_response_shape.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_llm_retry.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_mcp.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_mcp_http.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_memory_injection.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_modes.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_notify.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_policy_gates.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_reach.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_reasoning_budget.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_roles.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_schedule.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_self_knowledge.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_skills.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_steering.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_topology.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_v02.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_validity.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_vision.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_web.py +0 -0
- {autoforge_agent-0.4.0 → autoforge_agent-0.4.2}/tests/test_web_live.py +0 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# The sdist ships the test suite (setuptools picks up tests/test*.py on its own),
|
|
2
|
+
# so it has to ship everything that suite imports or reads:
|
|
3
|
+
# - conftest.py and the shared fakes the terminal and MCP tests drive
|
|
4
|
+
# - probes/: the captured generator replies test_json_repair reads by path
|
|
5
|
+
# Without this the tarball carried 39 test modules that could not be collected,
|
|
6
|
+
# plus two that failed on a missing fixture. Found by unpacking the release and
|
|
7
|
+
# running it -- which is now a job in ci.yml, and was briefly a job in
|
|
8
|
+
# tool-market's reproduce workflow before it moved to the repo that can fix it.
|
|
9
|
+
recursive-include tests *.py
|
|
10
|
+
recursive-include probes *.txt *.md *.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: autoforge-agent
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: Agent framework with verifiable self-made tools (the forge pipeline).
|
|
5
5
|
Author: Zhang Yangyi
|
|
6
6
|
License: MIT
|
|
@@ -11,6 +11,7 @@ Requires-Dist: requests>=2.28
|
|
|
11
11
|
Provides-Extra: dev
|
|
12
12
|
Requires-Dist: pytest>=7; extra == "dev"
|
|
13
13
|
Requires-Dist: pytest-xdist; extra == "dev"
|
|
14
|
+
Requires-Dist: pyyaml; extra == "dev"
|
|
14
15
|
|
|
15
16
|
# autoforge
|
|
16
17
|
|
|
@@ -39,7 +39,7 @@ from dataclasses import replace
|
|
|
39
39
|
from pathlib import Path
|
|
40
40
|
from typing import Any
|
|
41
41
|
|
|
42
|
-
from . import configfile, setup_wizard
|
|
42
|
+
from . import __version__, configfile, setup_wizard
|
|
43
43
|
from .agent import ForgeAgent
|
|
44
44
|
from .autonomy.policy import (CONFIRM_REQUIRED, FULL_FREEDOM, SUPERVISED,
|
|
45
45
|
AutonomyPolicy)
|
|
@@ -1020,7 +1020,11 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
1020
1020
|
p.add_argument("--policy", choices=list(POLICIES),
|
|
1021
1021
|
help="autonomy preset: full (default) or supervised "
|
|
1022
1022
|
"(AUTOFORGE_POLICY)")
|
|
1023
|
-
|
|
1023
|
+
# Read, not written down. This said "autoforge 0.4.0" as a literal, which is
|
|
1024
|
+
# the one place a user actually reads the number -- so it was the one place
|
|
1025
|
+
# that would go on reporting the old release after a bump, printing a
|
|
1026
|
+
# version the installed package did not have.
|
|
1027
|
+
p.add_argument("--version", action="version", version=f"autoforge {__version__}")
|
|
1024
1028
|
|
|
1025
1029
|
sub = p.add_subparsers(dest="command")
|
|
1026
1030
|
sub.add_parser("chat", help="talk to the agent in a REPL")
|
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>autoforge harness</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root{
|
|
9
|
+
--bg:#0b0d10; --panel:#12151a; --panel2:#171b21; --line:#22272f;
|
|
10
|
+
--fg:#d8dee6; --dim:#7c8794; --faint:#4d5560;
|
|
11
|
+
--blue:#4c9aff; --cyan:#37d3c4; --amber:#e3b341; --green:#4ec97e;
|
|
12
|
+
--orange:#f0883e; --red:#f25f5c; --purple:#a98bf0; --pink:#e879b9;
|
|
13
|
+
--mono:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,monospace;
|
|
14
|
+
}
|
|
15
|
+
*{box-sizing:border-box}
|
|
16
|
+
html,body{height:100%;margin:0}
|
|
17
|
+
body{
|
|
18
|
+
background:var(--bg);color:var(--fg);
|
|
19
|
+
font:14px/1.55 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;
|
|
20
|
+
display:flex;flex-direction:column;overflow:hidden;
|
|
21
|
+
}
|
|
22
|
+
button,input,select,textarea{font:inherit;color:inherit}
|
|
23
|
+
button{background:var(--panel2);border:1px solid var(--line);border-radius:6px;
|
|
24
|
+
padding:5px 11px;cursor:pointer;transition:.12s}
|
|
25
|
+
button:hover{border-color:#39414d;background:#1d222a}
|
|
26
|
+
button.primary{background:#1d4ed8;border-color:#2b5fe0;color:#fff}
|
|
27
|
+
button.primary:hover{background:#2559e8}
|
|
28
|
+
button.ghost{background:transparent}
|
|
29
|
+
button:disabled{opacity:.45;cursor:not-allowed}
|
|
30
|
+
|
|
31
|
+
/* ---- top bar ---- */
|
|
32
|
+
header{display:flex;align-items:center;gap:13px;padding:9px 15px;
|
|
33
|
+
border-bottom:1px solid var(--line);background:var(--panel);flex:none}
|
|
34
|
+
.brand{font-weight:650;letter-spacing:-.2px}
|
|
35
|
+
.brand span{color:var(--faint);font-weight:400}
|
|
36
|
+
.badge{font:11px/1 var(--mono);color:var(--dim);background:var(--panel2);
|
|
37
|
+
border:1px solid var(--line);border-radius:20px;padding:4px 9px;white-space:nowrap}
|
|
38
|
+
.spacer{flex:1}
|
|
39
|
+
select{background:var(--panel2);border:1px solid var(--line);border-radius:6px;padding:5px 8px}
|
|
40
|
+
|
|
41
|
+
/* ---- layout ---- */
|
|
42
|
+
main{flex:1;display:flex;min-height:0}
|
|
43
|
+
aside{width:225px;flex:none;border-right:1px solid var(--line);
|
|
44
|
+
background:var(--panel);display:flex;flex-direction:column;min-height:0}
|
|
45
|
+
aside h3{margin:0;padding:10px 13px 7px;font-size:11px;letter-spacing:.09em;
|
|
46
|
+
text-transform:uppercase;color:var(--faint);font-weight:600}
|
|
47
|
+
.list{overflow-y:auto;flex:1;padding:0 8px 10px}
|
|
48
|
+
.sess{padding:8px 10px;border-radius:6px;cursor:pointer;margin-bottom:3px;
|
|
49
|
+
border:1px solid transparent}
|
|
50
|
+
.sess:hover{background:var(--panel2)}
|
|
51
|
+
.sess.on{background:#182231;border-color:#24354d}
|
|
52
|
+
.sess .t{font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
53
|
+
.sess .m{font:10.5px/1.4 var(--mono);color:var(--faint);margin-top:2px}
|
|
54
|
+
|
|
55
|
+
section.chat{flex:1;display:flex;flex-direction:column;min-width:0;min-height:0}
|
|
56
|
+
|
|
57
|
+
/* ---- transcript ---- */
|
|
58
|
+
#log{flex:1;overflow-y:auto;padding:18px 22px;display:flex;
|
|
59
|
+
flex-direction:column;gap:11px}
|
|
60
|
+
.msg{max-width:min(860px,92%);border-radius:9px;padding:10px 14px;
|
|
61
|
+
border:1px solid var(--line);background:var(--panel)}
|
|
62
|
+
.msg .who{font:10.5px/1 var(--mono);letter-spacing:.08em;text-transform:uppercase;
|
|
63
|
+
color:var(--faint);margin-bottom:6px}
|
|
64
|
+
.msg.user{align-self:flex-end;background:#16202e;border-color:#22344a}
|
|
65
|
+
.msg.assistant{align-self:flex-start;border-color:#1f3b34}
|
|
66
|
+
.msg.assistant .who{color:var(--cyan)}
|
|
67
|
+
.msg.user .who{color:var(--blue)}
|
|
68
|
+
.msg.system{align-self:center;background:transparent;border-style:dashed;
|
|
69
|
+
color:var(--dim);font-size:12.5px;max-width:80%}
|
|
70
|
+
.msg.error{border-color:#5a2b2b;background:#1d1416}
|
|
71
|
+
.msg.error .who{color:var(--red)}
|
|
72
|
+
.msg pre{margin:6px 0 0;white-space:pre-wrap;word-break:break-word;
|
|
73
|
+
font:12.5px/1.55 var(--mono);background:#0d1014;border:1px solid var(--line);
|
|
74
|
+
border-radius:6px;padding:9px 11px;overflow-x:auto}
|
|
75
|
+
.msg .body{white-space:pre-wrap;word-break:break-word}
|
|
76
|
+
.empty{color:var(--faint);text-align:center;margin:auto;max-width:430px;line-height:1.9}
|
|
77
|
+
.empty code{font:12.5px var(--mono);color:var(--cyan);background:#0d1014;
|
|
78
|
+
border:1px solid var(--line);border-radius:4px;padding:2px 6px}
|
|
79
|
+
|
|
80
|
+
/* ---- checks table ---- */
|
|
81
|
+
table.checks{width:100%;border-collapse:collapse;margin-top:8px;font-size:12.5px}
|
|
82
|
+
table.checks td{padding:3px 7px;border-bottom:1px solid var(--line);
|
|
83
|
+
vertical-align:top}
|
|
84
|
+
table.checks td.k{font:11.5px var(--mono);color:var(--dim);white-space:nowrap;width:1%}
|
|
85
|
+
.pass{color:var(--green)}.fail{color:var(--red)}
|
|
86
|
+
|
|
87
|
+
/* ---- composer ---- */
|
|
88
|
+
.composer{flex:none;border-top:1px solid var(--line);background:var(--panel);
|
|
89
|
+
padding:11px 15px}
|
|
90
|
+
.row{display:flex;gap:9px;align-items:flex-end}
|
|
91
|
+
textarea{flex:1;resize:none;background:var(--panel2);border:1px solid var(--line);
|
|
92
|
+
border-radius:8px;padding:10px 12px;min-height:44px;max-height:190px;
|
|
93
|
+
font-family:inherit;outline:none}
|
|
94
|
+
textarea:focus{border-color:#31506f}
|
|
95
|
+
.hint{font:11px/1.6 var(--mono);color:var(--faint);margin-top:6px}
|
|
96
|
+
.hint b{color:var(--dim);font-weight:500}
|
|
97
|
+
|
|
98
|
+
/* ---- trace panel ---- */
|
|
99
|
+
aside.trace{width:335px;border-right:none;border-left:1px solid var(--line)}
|
|
100
|
+
.chips{display:flex;flex-wrap:wrap;gap:5px;padding:0 11px 9px}
|
|
101
|
+
.chip{font:10.5px/1 var(--mono);border:1px solid var(--line);border-radius:20px;
|
|
102
|
+
padding:4px 8px;cursor:pointer;color:var(--dim);background:transparent}
|
|
103
|
+
.chip.on{color:#0b0d10;border-color:transparent}
|
|
104
|
+
.tlist{overflow-y:auto;flex:1;padding:0 11px 14px}
|
|
105
|
+
.te{border-left:2px solid var(--line);padding:5px 0 6px 9px;margin-bottom:5px}
|
|
106
|
+
.te .h{font:10px/1.5 var(--mono);color:var(--faint);display:flex;gap:7px}
|
|
107
|
+
.te .x{font:12px/1.5 var(--mono);word-break:break-word;white-space:pre-wrap}
|
|
108
|
+
.te[data-s=user]{border-color:var(--blue)}
|
|
109
|
+
.te[data-s=assistant]{border-color:var(--cyan)}
|
|
110
|
+
.te[data-s=system]{border-color:var(--faint)}
|
|
111
|
+
.te[data-s=error]{border-color:var(--red)}
|
|
112
|
+
.te[data-s=tool_call]{border-color:var(--amber)}
|
|
113
|
+
.te[data-s=tool_result]{border-color:var(--green)}
|
|
114
|
+
.te[data-s=forge]{border-color:var(--orange)}
|
|
115
|
+
.te[data-s=subagent]{border-color:var(--pink)}
|
|
116
|
+
.te[data-s=selfmod]{border-color:var(--purple)}
|
|
117
|
+
.tools{padding:0 11px 12px;max-height:190px;overflow-y:auto}
|
|
118
|
+
.tool{display:flex;justify-content:space-between;gap:8px;font:11.5px var(--mono);
|
|
119
|
+
padding:3px 0;border-bottom:1px solid #191d23}
|
|
120
|
+
.tool .st{color:var(--faint)}
|
|
121
|
+
.live{width:6px;height:6px;border-radius:50%;background:var(--faint);display:inline-block}
|
|
122
|
+
.live.on{background:var(--green);box-shadow:0 0 7px var(--green)}
|
|
123
|
+
.hidden{display:none!important}
|
|
124
|
+
::-webkit-scrollbar{width:9px;height:9px}
|
|
125
|
+
::-webkit-scrollbar-thumb{background:#2a313a;border-radius:5px}
|
|
126
|
+
::-webkit-scrollbar-track{background:transparent}
|
|
127
|
+
</style>
|
|
128
|
+
</head>
|
|
129
|
+
<body>
|
|
130
|
+
|
|
131
|
+
<header>
|
|
132
|
+
<div class="brand">autoforge <span>harness</span></div>
|
|
133
|
+
<span class="badge" id="bModel">…</span>
|
|
134
|
+
<span class="badge" id="bBase"></span>
|
|
135
|
+
<select id="mode" title="runtime mode">
|
|
136
|
+
<option value="standard">standard — full forging agent</option>
|
|
137
|
+
<option value="minimal">minimal — two-tool coding agent</option>
|
|
138
|
+
</select>
|
|
139
|
+
<button class="primary" id="bNew">+ New session</button>
|
|
140
|
+
<div class="spacer"></div>
|
|
141
|
+
<span class="live" id="live" title="stream"></span>
|
|
142
|
+
<button class="ghost" id="bTrace">Trace</button>
|
|
143
|
+
<button class="ghost" id="bTools">Tools</button>
|
|
144
|
+
</header>
|
|
145
|
+
|
|
146
|
+
<main>
|
|
147
|
+
<aside>
|
|
148
|
+
<h3>Sessions</h3>
|
|
149
|
+
<div class="list" id="sessions"></div>
|
|
150
|
+
</aside>
|
|
151
|
+
|
|
152
|
+
<section class="chat">
|
|
153
|
+
<div id="log">
|
|
154
|
+
<div class="empty">
|
|
155
|
+
<div style="font-size:15px;color:var(--fg);margin-bottom:10px">Give the agent a need. It builds the tool.</div>
|
|
156
|
+
Try <code>I keep needing to normalise ISBN-10 and ISBN-13 identifiers</code><br>
|
|
157
|
+
then ask it to use the tool it just made.<br><br>
|
|
158
|
+
Everything the model sees shows up in the <b>Trace</b> panel, by source.
|
|
159
|
+
</div>
|
|
160
|
+
</div>
|
|
161
|
+
<div class="composer">
|
|
162
|
+
<div class="row">
|
|
163
|
+
<textarea id="input" rows="1"
|
|
164
|
+
placeholder="Tell the agent what you need… (⏎ send · ⇧⏎ newline)"></textarea>
|
|
165
|
+
<button class="primary" id="bSend">Send</button>
|
|
166
|
+
<button id="bForge" title="run the forge pipeline directly on this need">Forge</button>
|
|
167
|
+
</div>
|
|
168
|
+
<div class="hint"><b>Forge</b> runs the 5-check gate: execution · robustness · adversarial · trigger · negative</div>
|
|
169
|
+
</div>
|
|
170
|
+
</section>
|
|
171
|
+
|
|
172
|
+
<aside class="trace">
|
|
173
|
+
<h3>Trajectory <span id="tCount" style="color:var(--faint)"></span></h3>
|
|
174
|
+
<div class="chips" id="chips"></div>
|
|
175
|
+
<div class="tlist" id="trace"></div>
|
|
176
|
+
<h3>Tools</h3>
|
|
177
|
+
<div class="tools" id="tools"></div>
|
|
178
|
+
</aside>
|
|
179
|
+
</main>
|
|
180
|
+
|
|
181
|
+
<script>
|
|
182
|
+
const SOURCES = ["user","assistant","tool_call","tool_result","forge","system","error","subagent","selfmod","reasoning"];
|
|
183
|
+
const COLOR = {user:"--blue",assistant:"--cyan",tool_call:"--amber",tool_result:"--green",
|
|
184
|
+
forge:"--orange",system:"--faint",error:"--red",subagent:"--pink",selfmod:"--purple",
|
|
185
|
+
reasoning:"--purple"};
|
|
186
|
+
|
|
187
|
+
let current = null; // session id
|
|
188
|
+
let events = []; // events of the current session
|
|
189
|
+
let es = null; // EventSource
|
|
190
|
+
let hidden = new Set(); // source filter
|
|
191
|
+
const $ = (id) => document.getElementById(id);
|
|
192
|
+
|
|
193
|
+
// ---------------------------------------------------------------- api
|
|
194
|
+
async function api(path, opts) {
|
|
195
|
+
const res = await fetch(path, {
|
|
196
|
+
headers: {"Content-Type": "application/json"},
|
|
197
|
+
...opts,
|
|
198
|
+
});
|
|
199
|
+
if (!res.ok) {
|
|
200
|
+
let detail = res.statusText;
|
|
201
|
+
try { detail = (await res.json()).error || detail; } catch (e) {}
|
|
202
|
+
throw new Error(detail);
|
|
203
|
+
}
|
|
204
|
+
return res.status === 204 ? null : res.json();
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// ---------------------------------------------------------------- state
|
|
208
|
+
async function loadState() {
|
|
209
|
+
const s = await api("/api/state");
|
|
210
|
+
$("bModel").textContent = s.model || "?";
|
|
211
|
+
$("bBase").textContent = (s.base || "").replace(/^https?:\/\//, "");
|
|
212
|
+
$("bBase").title = s.base || "";
|
|
213
|
+
$("mode").value = s.default_mode || "standard";
|
|
214
|
+
document.title = `autoforge harness — ${s.model || ""}`;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
async function loadSessions() {
|
|
218
|
+
const {sessions} = await api("/api/sessions");
|
|
219
|
+
const box = $("sessions");
|
|
220
|
+
if (!sessions.length) {
|
|
221
|
+
box.innerHTML = `<div style="color:var(--faint);font:11.5px var(--mono);padding:4px 6px">none yet</div>`;
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
box.innerHTML = "";
|
|
225
|
+
for (const s of sessions) {
|
|
226
|
+
const el = document.createElement("div");
|
|
227
|
+
el.className = "sess" + (s.id === current ? " on" : "");
|
|
228
|
+
const when = new Date(s.updated * 1000).toLocaleTimeString();
|
|
229
|
+
el.innerHTML = `<div class="t"></div><div class="m">${s.mode} · ${s.events}ev · ${when}${s.busy ? " · ●" : ""}</div>`;
|
|
230
|
+
el.querySelector(".t").textContent = s.title;
|
|
231
|
+
el.onclick = () => openSession(s.id);
|
|
232
|
+
box.appendChild(el);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
async function loadTools() {
|
|
237
|
+
try {
|
|
238
|
+
const t = await api("/api/tools");
|
|
239
|
+
const box = $("tools");
|
|
240
|
+
const list = t.tools || [];
|
|
241
|
+
if (!list.length) {
|
|
242
|
+
box.innerHTML = `<div style="color:var(--faint);font:11.5px var(--mono)">none yet — forge one</div>`;
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
box.innerHTML = list.map(x =>
|
|
246
|
+
`<div class="tool"><span>${esc(x.name)}</span><span class="st">${esc(x.state || "")}</span></div>`
|
|
247
|
+
).join("");
|
|
248
|
+
} catch (e) {}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// ---------------------------------------------------------------- sessions
|
|
252
|
+
async function newSession() {
|
|
253
|
+
const mode = $("mode").value;
|
|
254
|
+
const s = await api("/api/sessions", {method: "POST", body: JSON.stringify({mode})});
|
|
255
|
+
await loadSessions();
|
|
256
|
+
openSession(s.id);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
async function openSession(id) {
|
|
260
|
+
if (es) { es.close(); es = null; }
|
|
261
|
+
current = id; events = [];
|
|
262
|
+
hidden = new Set(); renderChips();
|
|
263
|
+
$("log").innerHTML = "";
|
|
264
|
+
$("trace").innerHTML = "";
|
|
265
|
+
const s = await api(`/api/sessions/${id}`);
|
|
266
|
+
for (const ev of s.events) ingest(ev);
|
|
267
|
+
renderLog();
|
|
268
|
+
subscribe(id, events.length ? events[events.length - 1].seq : 0);
|
|
269
|
+
loadSessions();
|
|
270
|
+
$("input").focus();
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function subscribe(id, after) {
|
|
274
|
+
if (es) es.close();
|
|
275
|
+
es = new EventSource(`/api/sessions/${id}/stream?after=${after}`);
|
|
276
|
+
es.onopen = () => $("live").classList.add("on");
|
|
277
|
+
es.onerror = () => { $("live").classList.remove("on"); };
|
|
278
|
+
es.onmessage = (m) => {
|
|
279
|
+
let ev; try { ev = JSON.parse(m.data); } catch (e) { return; }
|
|
280
|
+
if (ev.seq <= (events.at(-1)?.seq || 0)) return;
|
|
281
|
+
ingest(ev); renderLog(); loadSessions();
|
|
282
|
+
if (ev.source === "forge" || ev.source === "tool_result") loadTools();
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// ---------------------------------------------------------------- render
|
|
287
|
+
function esc(s) { return String(s ?? "").replace(/[&<>"]/g, c =>
|
|
288
|
+
({"&":"&","<":"<",">":">",'"':"""}[c])); }
|
|
289
|
+
|
|
290
|
+
function ingest(ev) {
|
|
291
|
+
events.push(ev);
|
|
292
|
+
if (ev.source === "forge" && ev.checks) forges.push(ev);
|
|
293
|
+
const el = document.createElement("div");
|
|
294
|
+
el.className = "te";
|
|
295
|
+
el.dataset.s = ev.source;
|
|
296
|
+
el.dataset.seq = ev.seq;
|
|
297
|
+
if (hidden.has(ev.source)) el.classList.add("hidden");
|
|
298
|
+
const at = new Date(ev.t * 1000).toLocaleTimeString();
|
|
299
|
+
el.innerHTML = `<div class="h"><span style="color:var(${COLOR[ev.source] || "--dim"})">${esc(ev.source)}</span><span>${at}</span><span>#${ev.seq}</span></div><div class="x"></div>`;
|
|
300
|
+
el.querySelector(".x").textContent = ev.text || "";
|
|
301
|
+
$("trace").appendChild(el);
|
|
302
|
+
$("trace").scrollTop = $("trace").scrollHeight;
|
|
303
|
+
$("tCount").textContent = `(${events.length})`;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const forges = [];
|
|
307
|
+
|
|
308
|
+
function renderLog() {
|
|
309
|
+
const log = $("log");
|
|
310
|
+
const chatty = events.filter(e => ["user","assistant","system","error","forge"].includes(e.source));
|
|
311
|
+
if (!chatty.length) return;
|
|
312
|
+
log.innerHTML = "";
|
|
313
|
+
for (const ev of chatty) log.appendChild(bubble(ev));
|
|
314
|
+
log.scrollTop = log.scrollHeight;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function bubble(ev) {
|
|
318
|
+
const el = document.createElement("div");
|
|
319
|
+
const who = {user:"you", assistant:"agent", system:"system", error:"error", forge:"forge"}[ev.source] || ev.source;
|
|
320
|
+
el.className = "msg " + (ev.source === "error" ? "error" : ev.source);
|
|
321
|
+
el.innerHTML = `<div class="who">${esc(who)}</div><div class="body"></div>`;
|
|
322
|
+
el.querySelector(".body").textContent = ev.text || "";
|
|
323
|
+
if (ev.checks && ev.checks.length) {
|
|
324
|
+
const rows = ev.checks.map(c =>
|
|
325
|
+
`<tr><td class="k">r${c.round}</td><td class="k">${esc(c.name)}</td>
|
|
326
|
+
<td class="${c.passed ? "pass" : "fail"}">${c.passed ? "PASS" : "FAIL"}</td>
|
|
327
|
+
<td>${esc(c.detail)}</td></tr>`).join("");
|
|
328
|
+
el.insertAdjacentHTML("beforeend", `<table class="checks">${rows}</table>`);
|
|
329
|
+
}
|
|
330
|
+
if (ev.source === "error" && ev.detail) {
|
|
331
|
+
el.insertAdjacentHTML("beforeend", `<pre>${esc(ev.detail)}</pre>`);
|
|
332
|
+
}
|
|
333
|
+
return el;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
function renderChips() {
|
|
337
|
+
const box = $("chips");
|
|
338
|
+
box.innerHTML = "";
|
|
339
|
+
for (const s of SOURCES) {
|
|
340
|
+
const c = document.createElement("span");
|
|
341
|
+
c.className = "chip" + (hidden.has(s) ? "" : " on");
|
|
342
|
+
c.textContent = s;
|
|
343
|
+
if (!hidden.has(s)) c.style.background = `var(${COLOR[s]})`;
|
|
344
|
+
c.onclick = () => {
|
|
345
|
+
if (hidden.has(s)) hidden.delete(s); else hidden.add(s);
|
|
346
|
+
renderChips();
|
|
347
|
+
document.querySelectorAll(".te").forEach(el => {
|
|
348
|
+
el.classList.toggle("hidden", hidden.has(el.dataset.s));
|
|
349
|
+
});
|
|
350
|
+
};
|
|
351
|
+
box.appendChild(c);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// ---------------------------------------------------------------- actions
|
|
356
|
+
async function send(kind) {
|
|
357
|
+
if (!current) { await newSession(); }
|
|
358
|
+
const box = $("input");
|
|
359
|
+
const text = box.value.trim();
|
|
360
|
+
if (!text) return;
|
|
361
|
+
box.value = ""; box.style.height = "auto";
|
|
362
|
+
$("bSend").disabled = $("bForge").disabled = true;
|
|
363
|
+
try {
|
|
364
|
+
await api(`/api/sessions/${current}/${kind}`,
|
|
365
|
+
{method: "POST", body: JSON.stringify(kind === "send" ? {text} : {need: text})});
|
|
366
|
+
} catch (e) {
|
|
367
|
+
ingest({seq: (events.at(-1)?.seq || 0) + 1, t: Date.now() / 1000, source: "error", text: e.message});
|
|
368
|
+
renderLog();
|
|
369
|
+
} finally {
|
|
370
|
+
$("bSend").disabled = $("bForge").disabled = false;
|
|
371
|
+
setTimeout(() => { $("bSend").disabled = $("bForge").disabled = false; }, 400);
|
|
372
|
+
box.focus();
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// ---------------------------------------------------------------- wiring
|
|
377
|
+
$("bNew").onclick = newSession;
|
|
378
|
+
$("bSend").onclick = () => send("send");
|
|
379
|
+
$("bForge").onclick = () => send("forge");
|
|
380
|
+
$("bTrace").onclick = () => document.querySelector("aside.trace").classList.toggle("hidden");
|
|
381
|
+
$("bTools").onclick = () => { loadTools(); $("tools").scrollIntoView(); };
|
|
382
|
+
|
|
383
|
+
const input = $("input");
|
|
384
|
+
input.addEventListener("keydown", (e) => {
|
|
385
|
+
if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); send("send"); }
|
|
386
|
+
});
|
|
387
|
+
input.addEventListener("input", () => {
|
|
388
|
+
input.style.height = "auto";
|
|
389
|
+
input.style.height = Math.min(input.scrollHeight, 190) + "px";
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
(async function boot() {
|
|
393
|
+
try {
|
|
394
|
+
await loadState();
|
|
395
|
+
await loadSessions();
|
|
396
|
+
await loadTools();
|
|
397
|
+
} catch (e) {
|
|
398
|
+
ingesting = null;
|
|
399
|
+
console.error(e);
|
|
400
|
+
}
|
|
401
|
+
setInterval(loadSessions, 5000);
|
|
402
|
+
input.focus();
|
|
403
|
+
})();
|
|
404
|
+
</script>
|
|
405
|
+
</body>
|
|
406
|
+
</html>
|
|
@@ -84,20 +84,25 @@ __all__ = [
|
|
|
84
84
|
]
|
|
85
85
|
|
|
86
86
|
#: What this program calls itself when a server asks. Read from the installed
|
|
87
|
-
#: distribution so it cannot drift from `pyproject.toml`, with a
|
|
88
|
-
#:
|
|
89
|
-
#:
|
|
90
|
-
#:
|
|
91
|
-
#:
|
|
87
|
+
#: distribution so it cannot drift from `pyproject.toml`, with a fallback for the
|
|
88
|
+
#: source-checkout case where nothing is installed. The distribution is
|
|
89
|
+
#: `autoforge-agent` (the bare name `autoforge` on the index is somebody else's
|
|
90
|
+
#: package), so looking up `autoforge` here would not raise -- it would find
|
|
91
|
+
#: nothing installed and quietly serve a stale version forever.
|
|
92
|
+
#:
|
|
93
|
+
#: The fallback is deliberately not a plausible version. It used to be the
|
|
94
|
+
#: release number, which is worse than useless: on release day the fallback and
|
|
95
|
+
#: the real answer are the same string, so a broken lookup looks exactly like a
|
|
96
|
+
#: working one -- and a test that compares the two cannot tell them apart.
|
|
92
97
|
try:
|
|
93
98
|
from importlib.metadata import PackageNotFoundError as _NotFound
|
|
94
99
|
from importlib.metadata import version as _pkg_version
|
|
95
100
|
try:
|
|
96
101
|
_VERSION = _pkg_version("autoforge-agent")
|
|
97
102
|
except _NotFound:
|
|
98
|
-
_VERSION = "0.
|
|
103
|
+
_VERSION = "0.0.0+unknown"
|
|
99
104
|
except ImportError: # pragma: no cover
|
|
100
|
-
_VERSION = "0.
|
|
105
|
+
_VERSION = "0.0.0+unknown"
|
|
101
106
|
|
|
102
107
|
#: Per-page budget for what the model sees. Generous because this spends
|
|
103
108
|
#: context rather than API dollars, and a page cut to 5k is a page whose
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: autoforge-agent
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: Agent framework with verifiable self-made tools (the forge pipeline).
|
|
5
5
|
Author: Zhang Yangyi
|
|
6
6
|
License: MIT
|
|
@@ -11,6 +11,7 @@ Requires-Dist: requests>=2.28
|
|
|
11
11
|
Provides-Extra: dev
|
|
12
12
|
Requires-Dist: pytest>=7; extra == "dev"
|
|
13
13
|
Requires-Dist: pytest-xdist; extra == "dev"
|
|
14
|
+
Requires-Dist: pyyaml; extra == "dev"
|
|
14
15
|
|
|
15
16
|
# autoforge
|
|
16
17
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
MANIFEST.in
|
|
1
2
|
README.md
|
|
2
3
|
pyproject.toml
|
|
3
4
|
autoforge/__init__.py
|
|
@@ -65,12 +66,27 @@ autoforge/tools/registry.py
|
|
|
65
66
|
autoforge/tools/spec.py
|
|
66
67
|
autoforge/web/__init__.py
|
|
67
68
|
autoforge/web/server.py
|
|
69
|
+
autoforge/web/static/index.html
|
|
68
70
|
autoforge_agent.egg-info/PKG-INFO
|
|
69
71
|
autoforge_agent.egg-info/SOURCES.txt
|
|
70
72
|
autoforge_agent.egg-info/dependency_links.txt
|
|
71
73
|
autoforge_agent.egg-info/entry_points.txt
|
|
72
74
|
autoforge_agent.egg-info/requires.txt
|
|
73
75
|
autoforge_agent.egg-info/top_level.txt
|
|
76
|
+
probes/FINDINGS.md
|
|
77
|
+
probes/probe_forge_latency.py
|
|
78
|
+
probes/probe_gateway_context_503.py
|
|
79
|
+
probes/probe_gateway_empty.py
|
|
80
|
+
probes/probe_gateway_max_tokens.py
|
|
81
|
+
probes/probe_gateway_models.py
|
|
82
|
+
probes/probe_gateway_thinking.py
|
|
83
|
+
probes/probe_generator_reply.py
|
|
84
|
+
probes/probe_model_latency.py
|
|
85
|
+
probes/raw_generator_reply.txt
|
|
86
|
+
probes/raw_generator_reply_clean.txt
|
|
87
|
+
tests/_terminal.py
|
|
88
|
+
tests/conftest.py
|
|
89
|
+
tests/mcp_server_fixture.py
|
|
74
90
|
tests/test_autoforge.py
|
|
75
91
|
tests/test_browser.py
|
|
76
92
|
tests/test_cli.py
|