@danceiny/gotry 0.0.1-rc.15 → 0.0.1-rc.17

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.
Files changed (238) hide show
  1. package/README.md +51 -13
  2. package/README.zh-CN.md +26 -12
  3. package/bin/gotry-booking-copilot.js +53 -0
  4. package/bin/gotry-bootstrap.js +357 -8
  5. package/bin/gotry-inner.js +442 -60
  6. package/bin/gotry-runtime-resolution.d.ts +27 -0
  7. package/bin/gotry-runtime-resolution.js +50 -0
  8. package/bin/gotry.js +1 -1
  9. package/cordis.gotry-patch.yml +15 -1
  10. package/data/airline-airports.json +39 -0
  11. package/dist/capabilities/agent-reach-deep.js +1 -1
  12. package/dist/capabilities/agent-reach.js +1 -1
  13. package/dist/capabilities/anything.js +1 -1
  14. package/dist/capabilities/artifacts.js +1 -1
  15. package/dist/capabilities/effect.js +293 -0
  16. package/dist/capabilities/fact-log.js +41 -0
  17. package/dist/capabilities/flyai.js +20 -6
  18. package/dist/capabilities/hbcli.js +43 -1
  19. package/dist/capabilities/incident-log.js +1 -1
  20. package/dist/capabilities/model-override.js +18 -0
  21. package/dist/capabilities/opensky.js +1 -1
  22. package/dist/capabilities/resilience.js +90 -0
  23. package/dist/capabilities/session/action-cache.js +1 -1
  24. package/dist/capabilities/session/adapters/ctrip-flight.js +1 -1
  25. package/dist/capabilities/session/adapters/meituan-local.js +1 -1
  26. package/dist/capabilities/session/benchmark.js +2 -1
  27. package/dist/capabilities/session/extension-bridge.js +358 -0
  28. package/dist/capabilities/session/extension-channel.js +93 -0
  29. package/dist/capabilities/session/extension-distribution.js +234 -0
  30. package/dist/capabilities/session/extract.js +1 -1
  31. package/dist/capabilities/session/golden-score.js +92 -0
  32. package/dist/capabilities/session/health-watch.js +216 -0
  33. package/dist/capabilities/session/read-guard.js +1 -1
  34. package/dist/capabilities/session/static-flight-golden.js +137 -0
  35. package/dist/capabilities/session/transport.js +1 -1
  36. package/dist/capabilities/session/wizard.js +147 -0
  37. package/dist/capabilities/session-consent.js +1 -1
  38. package/dist/capabilities/session-login.js +83 -1
  39. package/dist/capabilities/session-search.js +111 -2
  40. package/dist/capabilities/weather.js +168 -46
  41. package/dist/data/session-golden-20.json +25 -0
  42. package/dist/data/sf-golden-manifest.json +102 -0
  43. package/dist/data/sf-static-routes.json +91 -0
  44. package/dist/scripts/action-cache-tests.js +1 -1
  45. package/dist/scripts/agent-planning-budget-e2e.js +227 -0
  46. package/dist/scripts/agent-planning-budget-tests.js +173 -0
  47. package/dist/scripts/agent-reach-deep-tests.js +1 -1
  48. package/dist/scripts/agent-reach-tests.js +1 -1
  49. package/dist/scripts/agent-reach-wrapper-tests.js +1 -1
  50. package/dist/scripts/anything-tests.js +1 -1
  51. package/dist/scripts/async-collect.js +1 -1
  52. package/dist/scripts/benchmark-environment-bridge-e2e.js +981 -0
  53. package/dist/scripts/benchmark-environment-bridge-tests.js +2544 -0
  54. package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +335 -0
  55. package/dist/scripts/booking-copilot-availability-policy-v2-tests.js +1355 -0
  56. package/dist/scripts/booking-copilot-bin-proof-tests.js +89 -0
  57. package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +113 -0
  58. package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +356 -0
  59. package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +557 -0
  60. package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +140 -0
  61. package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +202 -0
  62. package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +102 -0
  63. package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +374 -0
  64. package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +447 -0
  65. package/dist/scripts/booking-copilot-runtime-proof-tests.js +205 -0
  66. package/dist/scripts/booking-copilot-server-proof-tests.js +317 -0
  67. package/dist/scripts/booking-copilot-startup-proof-tests.js +283 -0
  68. package/dist/scripts/booking-copilot-v2-runtime-proof-tests.js +3935 -0
  69. package/dist/scripts/booking-saga-tests.js +1 -1
  70. package/dist/scripts/booking-surface-contract-proof-tests.js +393 -0
  71. package/dist/scripts/booking-surface-v2-contract-proof-tests.js +1174 -0
  72. package/dist/scripts/bootstrap-tests.js +59 -3
  73. package/dist/scripts/build-changelog.js +279 -0
  74. package/dist/scripts/changelog-tests.js +165 -0
  75. package/dist/scripts/companion-tests.js +1 -1
  76. package/dist/scripts/diff-test.js +1 -1
  77. package/dist/scripts/dsh-runtime-closure-tests.js +225 -0
  78. package/dist/scripts/dsh-runtime-closure.js +150 -0
  79. package/dist/scripts/effect-tests.js +474 -0
  80. package/dist/scripts/engine-run.js +1 -1
  81. package/dist/scripts/engine-tests.js +1 -1
  82. package/dist/scripts/evaluation-cadence-tests.js +347 -0
  83. package/dist/scripts/evaluation-contract-tests.js +574 -0
  84. package/dist/scripts/extension-distribution-cli.js +35 -0
  85. package/dist/scripts/extension-distribution-tests.js +341 -0
  86. package/dist/scripts/extension-tests.js +573 -0
  87. package/dist/scripts/fact-gate-tests.js +318 -0
  88. package/dist/scripts/flyai-tests.js +1 -1
  89. package/dist/scripts/hbcli-e2e-tests.js +180 -0
  90. package/dist/scripts/hbcli-tests.js +1 -1
  91. package/dist/scripts/health-watch-cli.js +51 -0
  92. package/dist/scripts/i18n-tests.js +1 -1
  93. package/dist/scripts/incident-tests.js +1 -1
  94. package/dist/scripts/journey-tests.js +1 -1
  95. package/dist/scripts/ledger-tests.js +1 -1
  96. package/dist/scripts/ledger-workflow-crash.js +1 -1
  97. package/dist/scripts/memory-capture-tests.js +1 -1
  98. package/dist/scripts/memory-decay-tests.js +1 -1
  99. package/dist/scripts/memory-metrics.js +1 -1
  100. package/dist/scripts/memory-value-report.js +1 -1
  101. package/dist/scripts/model-override-e2e.js +176 -0
  102. package/dist/scripts/nightly-evidence-tests.js +67 -4
  103. package/dist/scripts/nightly-evidence.js +59 -3
  104. package/dist/scripts/nudge-digest.js +1 -1
  105. package/dist/scripts/onboarding-tests.js +186 -0
  106. package/dist/scripts/opensky-check.js +1 -1
  107. package/dist/scripts/opensky-tests.js +1 -1
  108. package/dist/scripts/pnpm-dsh-closure-proof.js +20 -0
  109. package/dist/scripts/price-drift-tests.js +441 -0
  110. package/dist/scripts/price-drift-watch.js +491 -0
  111. package/dist/scripts/probe-poi-tests.js +1 -1
  112. package/dist/scripts/product-metrics.js +1 -1
  113. package/dist/scripts/publish-preverify.js +40 -4
  114. package/dist/scripts/realtime-pricing-tests.js +1 -1
  115. package/dist/scripts/replay-async.js +1 -1
  116. package/dist/scripts/replay-real.js +1 -1
  117. package/dist/scripts/replay.js +1 -1
  118. package/dist/scripts/session-attach-diagnose.js +1 -1
  119. package/dist/scripts/session-attach-poc.js +1 -1
  120. package/dist/scripts/session-benchmark.js +1 -1
  121. package/dist/scripts/session-extract-tests.js +1 -1
  122. package/dist/scripts/session-login.js +1 -1
  123. package/dist/scripts/session-tests.js +70 -20
  124. package/dist/scripts/sf-live-benchmark.js +338 -0
  125. package/dist/scripts/sf-live-cli-tests.js +21 -0
  126. package/dist/scripts/sf-soft-score-tests.js +108 -0
  127. package/dist/scripts/sf-summary.js +93 -0
  128. package/dist/scripts/skeleton-check.js +1 -1
  129. package/dist/scripts/skeleton-integration-test.js +1 -1
  130. package/dist/scripts/skills-contract-tests.js +1 -1
  131. package/dist/scripts/smoke-session-gate-tests.js +29 -0
  132. package/dist/scripts/smoke.js +154 -33
  133. package/dist/scripts/state-cli-tests.js +1 -1
  134. package/dist/scripts/state-cli.js +1 -1
  135. package/dist/scripts/static-golden-tests.js +299 -0
  136. package/dist/scripts/time-eval-tests.js +1 -1
  137. package/dist/scripts/travel-timeline-tests.js +1 -1
  138. package/dist/scripts/unified-tests.js +1 -1
  139. package/dist/scripts/weather-tests.js +694 -44
  140. package/dist/scripts/z3-race-tests.js +1 -1
  141. package/dist/src/artifact-gate.js +310 -0
  142. package/dist/src/benchmark-agent-conformance.js +370 -0
  143. package/dist/src/benchmark-environment-bridge.js +384 -0
  144. package/dist/src/benchmark-headless-child-diagnostics.js +173 -0
  145. package/dist/src/benchmark-tool-isolation.js +124 -0
  146. package/dist/src/bookable-facts.js +349 -0
  147. package/dist/src/booking-saga.js +1 -1
  148. package/dist/src/booking-surface/availability-policy-v2.js +830 -0
  149. package/dist/src/booking-surface/canonical-schema.js +113 -0
  150. package/dist/src/booking-surface/contracts-v2.js +89 -0
  151. package/dist/src/booking-surface/contracts.js +46 -0
  152. package/dist/src/booking-surface/dsh-planner.js +453 -0
  153. package/dist/src/booking-surface/dsh-plugin.js +93 -0
  154. package/dist/src/booking-surface/error-codes.js +94 -0
  155. package/dist/src/booking-surface/index.js +15 -0
  156. package/dist/src/booking-surface/profile.js +68 -0
  157. package/dist/src/booking-surface/runtime-v2.js +1771 -0
  158. package/dist/src/booking-surface/runtime.js +351 -0
  159. package/dist/src/booking-surface/server-v2.js +334 -0
  160. package/dist/src/booking-surface/server.js +302 -0
  161. package/dist/src/booking-surface/startup.js +159 -0
  162. package/dist/src/booking-surface/validation-v2.js +319 -0
  163. package/dist/src/booking-surface/validation.js +809 -0
  164. package/dist/src/bridge.js +1 -1
  165. package/dist/src/companions.js +1 -1
  166. package/dist/src/contracts.js +1 -1
  167. package/dist/src/dsh-llm.js +1 -1
  168. package/dist/src/engine.js +1 -1
  169. package/dist/src/evaluation-cadence.js +234 -0
  170. package/dist/src/evaluation-contracts.js +906 -0
  171. package/dist/src/i18n.js +1 -1
  172. package/dist/src/index.js +234 -60
  173. package/dist/src/journey.js +1 -1
  174. package/dist/src/loop.js +1 -1
  175. package/dist/src/memory-capture.js +1 -1
  176. package/dist/src/memory-decay.js +1 -1
  177. package/dist/src/memory-utility.js +1 -1
  178. package/dist/src/mock-llm.js +1 -1
  179. package/dist/src/model.js +1 -1
  180. package/dist/src/realtime-pricing.js +14 -7
  181. package/dist/src/slot-spec.js +1 -1
  182. package/dist/src/state-ledger.js +2 -1
  183. package/dist/src/time-anchor.js +1 -1
  184. package/dist/src/tool-budget.js +136 -0
  185. package/dist/src/tool-packet.js +1 -1
  186. package/dist/src/travel-slots.js +1 -1
  187. package/dist/src/travel-timeline.js +1 -1
  188. package/dist/src/unified.js +1 -1
  189. package/dist/src/wish-pool.js +1 -1
  190. package/dist/src/z3-shared.js +1 -1
  191. package/extension/README.md +50 -0
  192. package/extension/background.js +160 -0
  193. package/extension/content-bridge.js +41 -0
  194. package/extension/content-main.js +62 -0
  195. package/extension/manifest.json +32 -0
  196. package/package.json +291 -12
  197. package/schemas/booking.surface.v1.schema.json +927 -0
  198. package/schemas/booking.surface.v2.schema.json +61 -0
  199. package/ts/capabilities/fact-log.ts +54 -0
  200. package/ts/capabilities/flyai.ts +16 -3
  201. package/ts/capabilities/hbcli.ts +46 -0
  202. package/ts/capabilities/session/benchmark.ts +4 -1
  203. package/ts/capabilities/session/extension-bridge.ts +377 -0
  204. package/ts/capabilities/session/extension-channel.ts +95 -0
  205. package/ts/capabilities/session/extension-distribution.ts +264 -0
  206. package/ts/capabilities/session/golden-score.ts +139 -0
  207. package/ts/capabilities/session/health-watch.ts +257 -0
  208. package/ts/capabilities/session/static-flight-golden.ts +209 -0
  209. package/ts/capabilities/session/wizard.ts +140 -0
  210. package/ts/capabilities/session-login.ts +63 -2
  211. package/ts/capabilities/session-search.ts +105 -3
  212. package/ts/capabilities/weather.ts +141 -52
  213. package/ts/package.json +3 -3
  214. package/ts/src/artifact-gate.ts +365 -0
  215. package/ts/src/benchmark-agent-conformance.ts +448 -0
  216. package/ts/src/benchmark-environment-bridge.ts +348 -0
  217. package/ts/src/benchmark-headless-child-diagnostics.ts +184 -0
  218. package/ts/src/benchmark-tool-isolation.ts +166 -0
  219. package/ts/src/bookable-facts.ts +557 -0
  220. package/ts/src/booking-surface/availability-policy-v2.ts +523 -0
  221. package/ts/src/booking-surface/canonical-schema.js +113 -0
  222. package/ts/src/booking-surface/contracts-v2.ts +118 -0
  223. package/ts/src/booking-surface/contracts.ts +380 -0
  224. package/ts/src/booking-surface/dsh-planner.ts +452 -0
  225. package/ts/src/booking-surface/dsh-plugin.js +93 -0
  226. package/ts/src/booking-surface/error-codes.ts +101 -0
  227. package/ts/src/booking-surface/index.ts +12 -0
  228. package/ts/src/booking-surface/profile.ts +42 -0
  229. package/ts/src/booking-surface/runtime-v2.ts +1466 -0
  230. package/ts/src/booking-surface/runtime.ts +483 -0
  231. package/ts/src/booking-surface/server-v2.ts +247 -0
  232. package/ts/src/booking-surface/server.ts +324 -0
  233. package/ts/src/booking-surface/startup.ts +196 -0
  234. package/ts/src/booking-surface/validation-v2.ts +205 -0
  235. package/ts/src/booking-surface/validation.ts +453 -0
  236. package/ts/src/index.ts +161 -14
  237. package/ts/src/state-ledger.ts +1 -0
  238. package/ts/src/tool-budget.ts +165 -0
@@ -0,0 +1,227 @@
1
+ import assert from 'node:assert/strict';
2
+ import { createServer } from 'node:http';
3
+ import { existsSync, mkdtempSync, rmSync } from 'node:fs';
4
+ import { tmpdir } from 'node:os';
5
+ import { join } from 'node:path';
6
+ import { spawn } from 'node:child_process';
7
+ const ROOT = join(import.meta.dirname, '..', '..');
8
+ const TIMEOUT_MS = 90_000;
9
+ const TOOL = 'gotry_artifacts_list';
10
+ const EXHAUSTED = 'TOOL_BUDGET_EXHAUSTED';
11
+ function sse(data) {
12
+ return `data: ${JSON.stringify(data)}\n\n`;
13
+ }
14
+ function toolResponse(number) {
15
+ const count = number === 18 ? 2 : 1;
16
+ const calls = Array.from({
17
+ length: count
18
+ }, (_, index)=>({
19
+ index,
20
+ id: `budget-call-${number}-${index + 1}`,
21
+ type: 'function',
22
+ function: {
23
+ name: TOOL,
24
+ arguments: JSON.stringify({
25
+ query: {
26
+ limit: 1
27
+ }
28
+ })
29
+ }
30
+ }));
31
+ return sse({
32
+ id: `budget-${number}`,
33
+ object: 'chat.completion.chunk',
34
+ created: 1,
35
+ model: 'synthetic-budget-model',
36
+ choices: [
37
+ {
38
+ index: 0,
39
+ delta: {
40
+ role: 'assistant',
41
+ tool_calls: calls
42
+ },
43
+ finish_reason: null
44
+ }
45
+ ]
46
+ }) + sse({
47
+ id: `budget-${number}-finish`,
48
+ object: 'chat.completion.chunk',
49
+ created: 1,
50
+ model: 'synthetic-budget-model',
51
+ choices: [
52
+ {
53
+ index: 0,
54
+ delta: {},
55
+ finish_reason: 'tool_calls'
56
+ }
57
+ ]
58
+ }) + 'data: [DONE]\n\n';
59
+ }
60
+ function textResponse(text, id = 'budget-final') {
61
+ return sse({
62
+ id,
63
+ object: 'chat.completion.chunk',
64
+ created: 1,
65
+ model: 'synthetic-budget-model',
66
+ choices: [
67
+ {
68
+ index: 0,
69
+ delta: {
70
+ role: 'assistant',
71
+ content: text
72
+ },
73
+ finish_reason: null
74
+ }
75
+ ]
76
+ }) + sse({
77
+ id: `${id}-finish`,
78
+ object: 'chat.completion.chunk',
79
+ created: 1,
80
+ model: 'synthetic-budget-model',
81
+ choices: [
82
+ {
83
+ index: 0,
84
+ delta: {},
85
+ finish_reason: 'stop'
86
+ }
87
+ ]
88
+ }) + 'data: [DONE]\n\n';
89
+ }
90
+ async function startRelay() {
91
+ const bodies = [];
92
+ const plannerBodies = [];
93
+ const server = createServer((req, res)=>{
94
+ if (req.method !== 'POST' || !req.url?.endsWith('/chat/completions')) {
95
+ res.writeHead(404).end('not found');
96
+ return;
97
+ }
98
+ const chunks = [];
99
+ req.on('data', (chunk)=>chunks.push(Buffer.from(chunk)));
100
+ req.on('end', ()=>{
101
+ let body;
102
+ try {
103
+ body = JSON.parse(Buffer.concat(chunks).toString('utf8'));
104
+ } catch {
105
+ body = {};
106
+ }
107
+ bodies.push(body);
108
+ res.writeHead(200, {
109
+ 'content-type': 'text/event-stream',
110
+ 'cache-control': 'no-cache'
111
+ });
112
+ if (toolNames(body).includes(TOOL)) {
113
+ plannerBodies.push(body);
114
+ res.end(toolResponse(plannerBodies.length));
115
+ } else if (plannerBodies.length >= 18) {
116
+ res.end(textResponse('budget E2E final answer'));
117
+ } else {
118
+ res.end(textResponse('budget e2e title', 'budget-auxiliary'));
119
+ }
120
+ });
121
+ });
122
+ await new Promise((resolve)=>server.listen(0, '127.0.0.1', resolve));
123
+ return {
124
+ port: server.address().port,
125
+ bodies,
126
+ plannerBodies,
127
+ close: ()=>new Promise((resolve)=>server.close(()=>resolve()))
128
+ };
129
+ }
130
+ function allToolMessages(bodies) {
131
+ return bodies.flatMap((body)=>(body.messages ?? []).filter((message)=>message.role === 'tool'));
132
+ }
133
+ function toolNames(body) {
134
+ return (body.tools ?? []).map((tool)=>{
135
+ const fn = tool.function;
136
+ return String(fn?.name ?? tool.name ?? '');
137
+ }).filter(Boolean);
138
+ }
139
+ async function main() {
140
+ for (const file of [
141
+ 'dist/src/index.js',
142
+ 'dist/capabilities/artifacts.js'
143
+ ]){
144
+ assert.ok(existsSync(join(ROOT, file)), `missing ${file}; run node scripts/build-dist.mjs first`);
145
+ }
146
+ const relay = await startRelay();
147
+ const dshHome = mkdtempSync(join(tmpdir(), 'gotry-budget-dsh-home-'));
148
+ const childCwd = mkdtempSync(join(tmpdir(), 'gotry-budget-cwd-'));
149
+ let exitCode = null;
150
+ let output = '';
151
+ const configuredBin = process.env.GOTRY_BUDGET_E2E_BIN;
152
+ assert.ok(configuredBin && existsSync(configuredBin), 'GOTRY_BUDGET_E2E_BIN must point to the clean installed-package binary');
153
+ try {
154
+ const executable = configuredBin;
155
+ const executableArgs = [
156
+ 'exercise the tool budget'
157
+ ];
158
+ const childEnv = {
159
+ ...process.env
160
+ };
161
+ childEnv.DSH_HOME = dshHome;
162
+ childEnv.LLM_API_KEY = 'synthetic-e2e-key';
163
+ childEnv.LLM_BASE_URL = 'http://127.0.0.1:' + relay.port + '/v1';
164
+ childEnv.LLM_MODEL = 'synthetic-budget-model';
165
+ childEnv.GOTRY_LOCALE = 'zh-CN';
166
+ childEnv.GOTRY_DISABLE_OPTIONAL_CALENDAR = '1';
167
+ delete childEnv.GOTRY_LLM_MODEL;
168
+ const child = spawn(executable, executableArgs, {
169
+ cwd: childCwd,
170
+ env: childEnv,
171
+ stdio: [
172
+ 'ignore',
173
+ 'pipe',
174
+ 'pipe'
175
+ ]
176
+ });
177
+ child.stdout.on('data', (chunk)=>{
178
+ output += chunk.toString();
179
+ });
180
+ child.stderr.on('data', (chunk)=>{
181
+ output += chunk.toString();
182
+ });
183
+ exitCode = await new Promise((resolve)=>{
184
+ const timer = setTimeout(()=>{
185
+ child.kill('SIGKILL');
186
+ resolve(null);
187
+ }, TIMEOUT_MS);
188
+ child.once('exit', (code)=>{
189
+ clearTimeout(timer);
190
+ resolve(code);
191
+ });
192
+ });
193
+ } finally{
194
+ await relay.close();
195
+ rmSync(dshHome, {
196
+ recursive: true,
197
+ force: true
198
+ });
199
+ rmSync(childCwd, {
200
+ recursive: true,
201
+ force: true
202
+ });
203
+ }
204
+ assert.equal(exitCode, 0, `headless exit=${exitCode}; output tail=${output.slice(-1200)}`);
205
+ assert.equal(relay.plannerBodies.length, 18, `expected 18 tool-enabled planner requests, got ${relay.plannerBodies.length}; output tail=${output.slice(-12_000)}`);
206
+ const finalRequest = relay.bodies.at(-1);
207
+ const toolMessages = allToolMessages([
208
+ finalRequest
209
+ ]);
210
+ const normalResults = toolMessages.filter((message)=>!JSON.stringify(message).includes(EXHAUSTED));
211
+ const exhaustedResults = toolMessages.filter((message)=>JSON.stringify(message).includes(EXHAUSTED));
212
+ const toolMessageDiagnostic = JSON.stringify(toolMessages).slice(-12_000);
213
+ assert.equal(normalResults.length, 18, `exactly 18 real tool results/body dispatches; messages=${toolMessageDiagnostic}`);
214
+ assert.ok(normalResults.every((message)=>JSON.stringify(message).includes('无在册产物')), `all 18 bodies must return the registered artifact-list result; messages=${toolMessageDiagnostic}`);
215
+ assert.equal(exhaustedResults.length, 1, `19th call returns one structured exhaustion result; messages=${toolMessageDiagnostic}`);
216
+ assert.ok(JSON.stringify(exhaustedResults[0]).includes(EXHAUSTED));
217
+ assert.equal(exhaustedResults[0]?.tool_call_id, 'budget-call-18-2');
218
+ const finalNames = toolNames(finalRequest);
219
+ assert.ok(!finalNames.includes(TOOL), `final request inherited GoTry tool: ${finalNames.join(', ')}`);
220
+ assert.equal(finalNames.length, 0, `final request must be text-only, got ${finalNames.join(', ')}`);
221
+ assert.match(output, /budget E2E final answer/);
222
+ console.log(`agent planning budget E2E: OK (exit=${exitCode}, plannerRequests=${relay.plannerBodies.length}, allModelRequests=${relay.bodies.length}, realToolResults=${normalResults.length}, exhausted=${exhaustedResults.length})`);
223
+ }
224
+ await main();
225
+
226
+
227
+ //# sourceURL=ts/scripts/agent-planning-budget-e2e.ts
@@ -0,0 +1,173 @@
1
+ import assert from 'node:assert/strict';
2
+ import { createToolBudgetState, installToolBudget, TOOL_BUDGET_EXHAUSTED, toolBudgetDecision } from '../src/tool-budget.js';
3
+ const success = ()=>({
4
+ isError: false,
5
+ value: null,
6
+ content: []
7
+ });
8
+ const handlers = new Map();
9
+ const restricted = [];
10
+ const lifted = [];
11
+ const makeAgent = (id)=>({
12
+ id,
13
+ ctx: {
14
+ tools: {
15
+ restrict (filter) {
16
+ restricted.push({
17
+ agentId: id,
18
+ deny: [
19
+ ...filter.deny
20
+ ]
21
+ });
22
+ return ()=>lifted.push(id);
23
+ }
24
+ }
25
+ }
26
+ });
27
+ const ctx = {
28
+ tools: {
29
+ schemas: ()=>[
30
+ {
31
+ name: 'gotry_alpha'
32
+ },
33
+ {
34
+ name: 'gotry_beta'
35
+ }
36
+ ]
37
+ },
38
+ on (event, listener) {
39
+ const bucket = handlers.get(event) ?? [];
40
+ bucket.push(listener);
41
+ handlers.set(event, bucket);
42
+ return ()=>{};
43
+ }
44
+ };
45
+ installToolBudget(ctx);
46
+ const execute = handlers.get('tools/execute')?.[0];
47
+ const postExecute = handlers.get('tools/post-execute')?.[0];
48
+ const sessionEvent = handlers.get('session/event')?.[0];
49
+ const sessionDisposed = handlers.get('session/disposed')?.[0];
50
+ assert.ok(execute && postExecute && sessionEvent && sessionDisposed, 'all Cordis budget hooks register');
51
+ assert.deepEqual(toolBudgetDecision(18), {
52
+ kind: 'allow',
53
+ softSignal: false,
54
+ exhaustsBudget: true
55
+ });
56
+ const pureExhausted = toolBudgetDecision(19);
57
+ assert.equal(pureExhausted.kind, 'deny');
58
+ if (pureExhausted.kind === 'deny') assert.match(pureExhausted.reason, /TOOL_BUDGET_EXHAUSTED/);
59
+ const freshState = createToolBudgetState();
60
+ assert.equal(freshState.nextCall().callNumber, 1);
61
+ let directBodies = 0;
62
+ for(let i = 0; i < 25; i++){
63
+ const result = await execute({
64
+ token: Symbol(`direct-${i}`)
65
+ }, async ()=>{
66
+ directBodies++;
67
+ return success();
68
+ });
69
+ assert.equal(result.isError, false);
70
+ }
71
+ assert.equal(directBodies, 25);
72
+ const agent = makeAgent('agent-serial');
73
+ let serialBodies = 0;
74
+ let softSignals = 0;
75
+ for(let attempt = 1; attempt <= 18; attempt++){
76
+ const exec = {
77
+ token: Symbol(`serial-${attempt}`),
78
+ agent
79
+ };
80
+ const result = await execute(exec, async ()=>{
81
+ serialBodies++;
82
+ return success();
83
+ });
84
+ const post = await postExecute(exec, result, async ()=>({
85
+ kind: 'accept'
86
+ }));
87
+ const contextText = post.additionalContexts?.flatMap((item)=>item.content ?? []).map((item)=>item.text ?? '').join('\n') ?? '';
88
+ if (contextText.includes('TOOL_BUDGET_SOFT')) softSignals++;
89
+ }
90
+ assert.equal(serialBodies, 18);
91
+ assert.equal(softSignals, 1);
92
+ assert.equal(restricted.length, 0, 'same-step prepared calls remain resolvable until step/end');
93
+ let nineteenthBodyRan = false;
94
+ const nineteenth = await execute({
95
+ token: Symbol('serial-19'),
96
+ agent
97
+ }, async ()=>{
98
+ nineteenthBodyRan = true;
99
+ return success();
100
+ });
101
+ assert.equal(nineteenthBodyRan, false);
102
+ assert.equal(nineteenth.isError, true);
103
+ assert.deepEqual(nineteenth.error?.info, {
104
+ name: 'ToolBudgetError',
105
+ code: TOOL_BUDGET_EXHAUSTED
106
+ });
107
+ assert.match(nineteenth.content[0]?.text ?? '', /TOOL_BUDGET_EXHAUSTED/);
108
+ assert.match(nineteenth.additionalContexts?.[0]?.content?.[0]?.text ?? '', /Produce the final answer/);
109
+ sessionEvent({
110
+ id: agent.id
111
+ }, {
112
+ type: 'step/end'
113
+ });
114
+ assert.deepEqual(restricted.at(-1), {
115
+ agentId: agent.id,
116
+ deny: [
117
+ 'gotry_alpha',
118
+ 'gotry_beta'
119
+ ]
120
+ });
121
+ sessionEvent({
122
+ id: agent.id
123
+ }, {
124
+ type: 'turn/end'
125
+ });
126
+ assert.equal(lifted.at(-1), agent.id);
127
+ sessionEvent({
128
+ id: agent.id
129
+ }, {
130
+ type: 'turn/start'
131
+ });
132
+ const afterReset = await execute({
133
+ token: Symbol('new-turn-1'),
134
+ agent
135
+ }, async ()=>success());
136
+ assert.equal(afterReset.isError, false);
137
+ const parallelAgent = makeAgent('agent-parallel');
138
+ let parallelBodies = 0;
139
+ const parallelResults = await Promise.all(Array.from({
140
+ length: 19
141
+ }, async (_, index)=>{
142
+ return execute({
143
+ token: Symbol(`parallel-${index + 1}`),
144
+ agent: parallelAgent
145
+ }, async ()=>{
146
+ parallelBodies++;
147
+ await Promise.resolve();
148
+ return success();
149
+ });
150
+ }));
151
+ assert.equal(parallelBodies, 18);
152
+ assert.equal(parallelResults.filter((result)=>result.isError).length, 1);
153
+ assert.equal(parallelResults.find((result)=>result.isError)?.error?.info?.code, TOOL_BUDGET_EXHAUSTED);
154
+ sessionEvent({
155
+ id: parallelAgent.id
156
+ }, {
157
+ type: 'step/end'
158
+ });
159
+ assert.deepEqual(restricted.at(-1), {
160
+ agentId: parallelAgent.id,
161
+ deny: [
162
+ 'gotry_alpha',
163
+ 'gotry_beta'
164
+ ]
165
+ });
166
+ sessionDisposed({
167
+ id: parallelAgent.id
168
+ });
169
+ assert.equal(lifted.at(-1), parallelAgent.id);
170
+ console.log('agent planning tool budget tests: OK (Cordis execute/post/lifecycle/parallel integration)');
171
+
172
+
173
+ //# sourceURL=ts/scripts/agent-planning-budget-tests.ts
@@ -51,4 +51,4 @@ import { videoSubtitle, githubSearch } from '../capabilities/agent-reach-deep.js
51
51
  }console.log('\nAGENT-REACH DEEP TESTS: 4/4 OK(yt-dlp/gh 可选工具,不装则降级)');
52
52
 
53
53
 
54
- //# sourceURL=/Users/bytedance/work/gotry/ts/scripts/agent-reach-deep-tests.ts
54
+ //# sourceURL=ts/scripts/agent-reach-deep-tests.ts
@@ -35,4 +35,4 @@ import { readUrl } from '../capabilities/agent-reach.js';
35
35
  }console.log('\nAGENT-REACH TESTS: 3/3 OK(readUrl 薄壳;上游真读见 wrapper 套)');
36
36
 
37
37
 
38
- //# sourceURL=/Users/bytedance/work/gotry/ts/scripts/agent-reach-tests.ts
38
+ //# sourceURL=ts/scripts/agent-reach-tests.ts
@@ -80,4 +80,4 @@ import { reach, reachStatus } from '../capabilities/agent-reach.js';
80
80
  }console.log('\nAGENT-REACH WRAPPER TESTS: 7/7 OK(反射桥 + doctor 透传 + 自描述错误)');
81
81
 
82
82
 
83
- //# sourceURL=/Users/bytedance/work/gotry/ts/scripts/agent-reach-wrapper-tests.ts
83
+ //# sourceURL=ts/scripts/agent-reach-wrapper-tests.ts
@@ -92,4 +92,4 @@ while :; do sleep 5; done
92
92
  }
93
93
 
94
94
 
95
- //# sourceURL=/Users/bytedance/work/gotry/ts/scripts/anything-tests.ts
95
+ //# sourceURL=ts/scripts/anything-tests.ts
@@ -62,4 +62,4 @@ console.log(JSON.stringify(outcome));
62
62
  process.exitCode = outcome.status === 'succeeded' ? 0 : 2;
63
63
 
64
64
 
65
- //# sourceURL=/Users/bytedance/work/gotry/ts/scripts/async-collect.ts
65
+ //# sourceURL=ts/scripts/async-collect.ts