@yolk-sdk/agent 0.1.0-canary.106 → 0.1.0-canary.108
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.
- package/README.md +112 -45
- package/dist/compaction/window.d.mts.map +1 -1
- package/dist/compaction/window.mjs +8 -2
- package/dist/compaction/window.mjs.map +1 -1
- package/dist/loop/index.d.mts +2 -1
- package/dist/loop/index.mjs +2 -1
- package/dist/loop/instructions.d.mts +39 -0
- package/dist/loop/instructions.d.mts.map +1 -0
- package/dist/loop/instructions.mjs +42 -0
- package/dist/loop/instructions.mjs.map +1 -0
- package/dist/loop/run.d.mts +15 -2
- package/dist/loop/run.d.mts.map +1 -1
- package/dist/loop/run.mjs +35 -17
- package/dist/loop/run.mjs.map +1 -1
- package/dist/loop/services/llm-provider.d.mts +23 -2
- package/dist/loop/services/llm-provider.d.mts.map +1 -1
- package/dist/loop/services/llm-provider.mjs.map +1 -1
- package/dist/protocol/index.d.mts +4 -3
- package/dist/protocol/index.d.mts.map +1 -1
- package/dist/protocol/index.mjs +4 -3
- package/dist/protocol/message.d.mts +34 -1
- package/dist/protocol/message.d.mts.map +1 -1
- package/dist/protocol/message.mjs +39 -2
- package/dist/protocol/message.mjs.map +1 -1
- package/dist/protocol/tool-search.d.mts +31 -0
- package/dist/protocol/tool-search.d.mts.map +1 -0
- package/dist/protocol/tool-search.mjs +42 -0
- package/dist/protocol/tool-search.mjs.map +1 -0
- package/dist/protocol/tool.d.mts +19 -6
- package/dist/protocol/tool.d.mts.map +1 -1
- package/dist/protocol/tool.mjs +17 -4
- package/dist/protocol/tool.mjs.map +1 -1
- package/dist/providers/anthropic/claude-provider.d.mts +22 -2
- package/dist/providers/anthropic/claude-provider.d.mts.map +1 -1
- package/dist/providers/anthropic/claude-provider.mjs.map +1 -1
- package/dist/providers/anthropic/claude.d.mts +8 -2
- package/dist/providers/anthropic/claude.d.mts.map +1 -1
- package/dist/providers/anthropic/claude.mjs +7 -1
- package/dist/providers/anthropic/claude.mjs.map +1 -1
- package/dist/providers/anthropic/conformance/cases.d.mts.map +1 -1
- package/dist/providers/anthropic/conformance/cases.mjs +3 -2
- package/dist/providers/anthropic/conformance/cases.mjs.map +1 -1
- package/dist/providers/anthropic/conformance/error-envelope.d.mts.map +1 -1
- package/dist/providers/anthropic/conformance/error-envelope.mjs +7 -2
- package/dist/providers/anthropic/conformance/error-envelope.mjs.map +1 -1
- package/dist/providers/anthropic/conformance/max-tokens.d.mts.map +1 -1
- package/dist/providers/anthropic/conformance/max-tokens.mjs +7 -2
- package/dist/providers/anthropic/conformance/max-tokens.mjs.map +1 -1
- package/dist/providers/anthropic/conformance/plain-text.d.mts.map +1 -1
- package/dist/providers/anthropic/conformance/plain-text.mjs +7 -2
- package/dist/providers/anthropic/conformance/plain-text.mjs.map +1 -1
- package/dist/providers/anthropic/conformance/thinking-before-text.d.mts.map +1 -1
- package/dist/providers/anthropic/conformance/thinking-before-text.mjs +7 -2
- package/dist/providers/anthropic/conformance/thinking-before-text.mjs.map +1 -1
- package/dist/providers/anthropic/conformance/tool-use-input-deltas.d.mts.map +1 -1
- package/dist/providers/anthropic/conformance/tool-use-input-deltas.mjs +9 -3
- package/dist/providers/anthropic/conformance/tool-use-input-deltas.mjs.map +1 -1
- package/dist/providers/anthropic-messages-provider-internal.d.mts +6 -3
- package/dist/providers/anthropic-messages-provider-internal.d.mts.map +1 -1
- package/dist/providers/anthropic-messages-provider-internal.mjs +6 -1
- package/dist/providers/anthropic-messages-provider-internal.mjs.map +1 -1
- package/dist/providers/anthropic-provider-internal.d.mts +28 -2
- package/dist/providers/anthropic-provider-internal.d.mts.map +1 -1
- package/dist/providers/anthropic-provider-internal.mjs +104 -7
- package/dist/providers/anthropic-provider-internal.mjs.map +1 -1
- package/dist/providers/cache-key-headers.d.mts +7 -0
- package/dist/providers/cache-key-headers.d.mts.map +1 -0
- package/dist/providers/cache-key-headers.mjs +10 -0
- package/dist/providers/cache-key-headers.mjs.map +1 -0
- package/dist/providers/openai/codex-provider.d.mts +2 -0
- package/dist/providers/openai/codex-provider.d.mts.map +1 -1
- package/dist/providers/openai/codex-provider.mjs +6 -0
- package/dist/providers/openai/codex-provider.mjs.map +1 -1
- package/dist/providers/openai/provider.d.mts +6 -0
- package/dist/providers/openai/provider.d.mts.map +1 -1
- package/dist/providers/openai/provider.mjs +18 -5
- package/dist/providers/openai/provider.mjs.map +1 -1
- package/dist/providers/openai-responses-provider-internal.d.mts +8 -1
- package/dist/providers/openai-responses-provider-internal.d.mts.map +1 -1
- package/dist/providers/openai-responses-provider-internal.mjs +19 -3
- package/dist/providers/openai-responses-provider-internal.mjs.map +1 -1
- package/dist/providers/opencode/conformance/messages-plain-text.d.mts.map +1 -1
- package/dist/providers/opencode/conformance/messages-plain-text.mjs +7 -2
- package/dist/providers/opencode/conformance/messages-plain-text.mjs.map +1 -1
- package/dist/providers/opencode/go-provider.d.mts.map +1 -1
- package/dist/providers/opencode/go-provider.mjs +6 -2
- package/dist/providers/opencode/go-provider.mjs.map +1 -1
- package/dist/providers/vercel/ai-gateway-provider.d.mts.map +1 -1
- package/dist/providers/vercel/ai-gateway-provider.mjs +8 -8
- package/dist/providers/vercel/ai-gateway-provider.mjs.map +1 -1
- package/dist/providers/vercel/conformance/cases.d.mts.map +1 -1
- package/dist/providers/vercel/conformance/cases.mjs.map +1 -1
- package/dist/providers/xai/grok-provider.d.mts +2 -0
- package/dist/providers/xai/grok-provider.d.mts.map +1 -1
- package/dist/providers/xai/grok-provider.mjs +6 -0
- package/dist/providers/xai/grok-provider.mjs.map +1 -1
- package/dist/react/chat-actions.d.mts +20 -20
- package/dist/react/chat-actions.d.mts.map +1 -1
- package/dist/react/chat-messages.d.mts +6 -0
- package/dist/react/chat-messages.d.mts.map +1 -1
- package/dist/react/chat-messages.mjs +18 -4
- package/dist/react/chat-messages.mjs.map +1 -1
- package/dist/runtime/run-runtime.d.mts +7 -2
- package/dist/runtime/run-runtime.d.mts.map +1 -1
- package/dist/runtime/run-runtime.mjs +18 -13
- package/dist/runtime/run-runtime.mjs.map +1 -1
- package/dist/skillset/merge.d.mts +3 -3
- package/dist/tools/index.d.mts +3 -2
- package/dist/tools/index.mjs +2 -1
- package/dist/tools/plan-runtime.d.mts.map +1 -1
- package/dist/tools/plan-runtime.mjs +20 -5
- package/dist/tools/plan-runtime.mjs.map +1 -1
- package/dist/tools/registry.d.mts +26 -5
- package/dist/tools/registry.d.mts.map +1 -1
- package/dist/tools/registry.mjs +58 -8
- package/dist/tools/registry.mjs.map +1 -1
- package/dist/tools/tool-search.d.mts +33 -0
- package/dist/tools/tool-search.d.mts.map +1 -0
- package/dist/tools/tool-search.mjs +119 -0
- package/dist/tools/tool-search.mjs.map +1 -0
- package/package.json +2 -2
- package/src/compaction/window.ts +16 -1
- package/src/loop/index.ts +2 -0
- package/src/loop/instructions.ts +76 -0
- package/src/loop/run.ts +65 -17
- package/src/loop/services/llm-provider.ts +23 -2
- package/src/protocol/index.ts +13 -0
- package/src/protocol/message.ts +61 -1
- package/src/protocol/tool-search.ts +72 -0
- package/src/protocol/tool.ts +30 -6
- package/src/providers/anthropic/claude-provider.ts +25 -1
- package/src/providers/anthropic/claude.ts +7 -1
- package/src/providers/anthropic/conformance/cases.ts +3 -2
- package/src/providers/anthropic/conformance/error-envelope.ts +13 -2
- package/src/providers/anthropic/conformance/max-tokens.ts +13 -2
- package/src/providers/anthropic/conformance/plain-text.ts +13 -2
- package/src/providers/anthropic/conformance/thinking-before-text.ts +13 -2
- package/src/providers/anthropic/conformance/tool-use-input-deltas.ts +16 -2
- package/src/providers/anthropic-messages-provider-internal.ts +11 -1
- package/src/providers/anthropic-provider-internal.ts +177 -13
- package/src/providers/cache-key-headers.ts +13 -0
- package/src/providers/openai/codex-provider.ts +11 -0
- package/src/providers/openai/provider.ts +40 -5
- package/src/providers/openai-responses-provider-internal.ts +31 -3
- package/src/providers/opencode/conformance/messages-plain-text.ts +13 -2
- package/src/providers/opencode/go-provider.ts +8 -2
- package/src/providers/vercel/ai-gateway-provider.ts +18 -14
- package/src/providers/vercel/conformance/cases.ts +2 -1
- package/src/providers/xai/grok-provider.ts +10 -0
- package/src/react/chat-messages.ts +42 -3
- package/src/runtime/run-runtime.ts +38 -13
- package/src/tools/index.ts +10 -0
- package/src/tools/plan-runtime.ts +27 -9
- package/src/tools/registry.ts +184 -14
- package/src/tools/tool-search.ts +183 -0
package/README.md
CHANGED
|
@@ -20,47 +20,47 @@ Published package metadata requires Node.js 22+.
|
|
|
20
20
|
|
|
21
21
|
## Subpaths
|
|
22
22
|
|
|
23
|
-
| Subpath | Purpose
|
|
24
|
-
| -------------------------------------------------------- |
|
|
25
|
-
| `@yolk-sdk/agent/protocol` | Wire messages, events, content, usage, tool schemas
|
|
26
|
-
| `@yolk-sdk/agent/loop` | Stateless LLM/tool loop
|
|
27
|
-
| `@yolk-sdk/agent/loop/testing` | Faux provider and tool executor test helpers
|
|
28
|
-
| `@yolk-sdk/agent/runtime` | Transcript or append-backed runtime orchestration
|
|
29
|
-
| `@yolk-sdk/agent/client` | HTTP/NDJSON transport, HITL resume, retry/error state helpers
|
|
30
|
-
| `@yolk-sdk/agent/compaction` | Host-owned compaction budgets, checkpoints, formatting, retry
|
|
31
|
-
| `@yolk-sdk/agent/classification` | Classifier model contract: typed questions, answers, usage, errors
|
|
32
|
-
| `@yolk-sdk/agent/tools` | Tool registry, typed inputs, interactions, subagents/questions, durable tool ledger, staged tool plans, tool change previews |
|
|
33
|
-
| `@yolk-sdk/agent/react` | Headless React chat hook, reducer, selectors, and render model
|
|
34
|
-
| `@yolk-sdk/agent/oauth` | Provider-neutral OAuth token and broker contracts
|
|
35
|
-
| `@yolk-sdk/agent/providers/openai` | OpenAI/Codex OAuth and broker helpers
|
|
36
|
-
| `@yolk-sdk/agent/providers/openai/codex` | OpenAI Codex request and auth helpers
|
|
37
|
-
| `@yolk-sdk/agent/providers/openai/codex-usage` | Codex subscription-allowance snapshots
|
|
38
|
-
| `@yolk-sdk/agent/providers/openai/codex-provider` | Codex LLM provider factory
|
|
39
|
-
| `@yolk-sdk/agent/providers/openai/provider` | OpenAI-compatible LLM provider factory
|
|
40
|
-
| `@yolk-sdk/agent/providers/openai/conformance` | Synthetic OpenAI chat, Codex Responses, and Codex usage fixtures and conformance cases
|
|
41
|
-
| `@yolk-sdk/agent/providers/openai/realtime` | OpenAI Realtime session config and event codecs
|
|
42
|
-
| `@yolk-sdk/agent/providers/openai/speech` | OpenAI text-to-speech and transcription adapters
|
|
43
|
-
| `@yolk-sdk/agent/providers/vercel/ai-gateway-provider` | Vercel AI Gateway Chat Completions provider factory
|
|
44
|
-
| `@yolk-sdk/agent/providers/vercel/ai-gateway-classifier` | Vercel AI Gateway classifier (`POST /v1/evaluate`) layer
|
|
45
|
-
| `@yolk-sdk/agent/providers/vercel/conformance` | Verified Gateway chat fixtures, synthetic classifier fixtures, and conformance cases
|
|
46
|
-
| `@yolk-sdk/agent/providers/opencode/go-provider` | OpenCode Go Chat Completions, Messages, and Responses provider
|
|
47
|
-
| `@yolk-sdk/agent/providers/opencode/usage` | OpenCode Go subscription-allowance snapshots
|
|
48
|
-
| `@yolk-sdk/agent/providers/opencode/conformance` | Synthetic OpenCode Go (per protocol, commentary replay, usage) fixtures and conformance cases
|
|
49
|
-
| `@yolk-sdk/agent/providers/anthropic` | Anthropic/Claude OAuth and broker helpers
|
|
50
|
-
| `@yolk-sdk/agent/providers/anthropic/claude` | Claude request and auth helpers
|
|
51
|
-
| `@yolk-sdk/agent/providers/anthropic/usage` | Claude subscription-allowance snapshots
|
|
52
|
-
| `@yolk-sdk/agent/providers/anthropic/claude-provider` | Claude LLM provider factory
|
|
53
|
-
| `@yolk-sdk/agent/providers/anthropic/conformance` | Synthetic Anthropic Messages and Claude usage fixtures and conformance cases
|
|
54
|
-
| `@yolk-sdk/agent/providers/xai` | Grok subscription OAuth and token broker helpers
|
|
55
|
-
| `@yolk-sdk/agent/providers/xai/grok` | Grok subscription request and auth helpers
|
|
56
|
-
| `@yolk-sdk/agent/providers/xai/grok-provider` | Grok subscription LLM provider factory
|
|
57
|
-
| `@yolk-sdk/agent/providers/xai/usage` | Grok subscription-allowance snapshots
|
|
58
|
-
| `@yolk-sdk/agent/providers/xai/conformance` | Synthetic Grok Responses and Grok usage fixtures and conformance cases
|
|
59
|
-
| `@yolk-sdk/agent/providers/subscription-usage` | Shared allowance snapshot and safe error schemas
|
|
60
|
-
| `@yolk-sdk/agent/skillset` | Portable skill and slash-command parsing/catalogs
|
|
61
|
-
| `@yolk-sdk/agent/voice` | Voice protocol, controller, tool handler, projection, speech
|
|
62
|
-
| `@yolk-sdk/agent/voice/browser` | Browser WebRTC voice transport
|
|
63
|
-
| `@yolk-sdk/agent/voice/react` | Headless browser voice React hook
|
|
23
|
+
| Subpath | Purpose |
|
|
24
|
+
| -------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
25
|
+
| `@yolk-sdk/agent/protocol` | Wire messages, events, content, usage, tool schemas |
|
|
26
|
+
| `@yolk-sdk/agent/loop` | Stateless LLM/tool loop, host instructions |
|
|
27
|
+
| `@yolk-sdk/agent/loop/testing` | Faux provider and tool executor test helpers |
|
|
28
|
+
| `@yolk-sdk/agent/runtime` | Transcript or append-backed runtime orchestration |
|
|
29
|
+
| `@yolk-sdk/agent/client` | HTTP/NDJSON transport, HITL resume, retry/error state helpers |
|
|
30
|
+
| `@yolk-sdk/agent/compaction` | Host-owned compaction budgets, checkpoints, formatting, retry |
|
|
31
|
+
| `@yolk-sdk/agent/classification` | Classifier model contract: typed questions, answers, usage, errors |
|
|
32
|
+
| `@yolk-sdk/agent/tools` | Tool registry, deferred loading (`tool_search`), typed inputs, interactions, subagents/questions, durable tool ledger, staged tool plans, tool change previews |
|
|
33
|
+
| `@yolk-sdk/agent/react` | Headless React chat hook, reducer, selectors, and render model |
|
|
34
|
+
| `@yolk-sdk/agent/oauth` | Provider-neutral OAuth token and broker contracts |
|
|
35
|
+
| `@yolk-sdk/agent/providers/openai` | OpenAI/Codex OAuth and broker helpers |
|
|
36
|
+
| `@yolk-sdk/agent/providers/openai/codex` | OpenAI Codex request and auth helpers |
|
|
37
|
+
| `@yolk-sdk/agent/providers/openai/codex-usage` | Codex subscription-allowance snapshots |
|
|
38
|
+
| `@yolk-sdk/agent/providers/openai/codex-provider` | Codex LLM provider factory |
|
|
39
|
+
| `@yolk-sdk/agent/providers/openai/provider` | OpenAI-compatible LLM provider factory |
|
|
40
|
+
| `@yolk-sdk/agent/providers/openai/conformance` | Synthetic OpenAI chat, Codex Responses, and Codex usage fixtures and conformance cases |
|
|
41
|
+
| `@yolk-sdk/agent/providers/openai/realtime` | OpenAI Realtime session config and event codecs |
|
|
42
|
+
| `@yolk-sdk/agent/providers/openai/speech` | OpenAI text-to-speech and transcription adapters |
|
|
43
|
+
| `@yolk-sdk/agent/providers/vercel/ai-gateway-provider` | Vercel AI Gateway Chat Completions provider factory |
|
|
44
|
+
| `@yolk-sdk/agent/providers/vercel/ai-gateway-classifier` | Vercel AI Gateway classifier (`POST /v1/evaluate`) layer |
|
|
45
|
+
| `@yolk-sdk/agent/providers/vercel/conformance` | Verified Gateway chat fixtures, synthetic classifier fixtures, and conformance cases |
|
|
46
|
+
| `@yolk-sdk/agent/providers/opencode/go-provider` | OpenCode Go Chat Completions, Messages, and Responses provider |
|
|
47
|
+
| `@yolk-sdk/agent/providers/opencode/usage` | OpenCode Go subscription-allowance snapshots |
|
|
48
|
+
| `@yolk-sdk/agent/providers/opencode/conformance` | Synthetic OpenCode Go (per protocol, commentary replay, usage) fixtures and conformance cases |
|
|
49
|
+
| `@yolk-sdk/agent/providers/anthropic` | Anthropic/Claude OAuth and broker helpers |
|
|
50
|
+
| `@yolk-sdk/agent/providers/anthropic/claude` | Claude request and auth helpers |
|
|
51
|
+
| `@yolk-sdk/agent/providers/anthropic/usage` | Claude subscription-allowance snapshots |
|
|
52
|
+
| `@yolk-sdk/agent/providers/anthropic/claude-provider` | Claude LLM provider factory |
|
|
53
|
+
| `@yolk-sdk/agent/providers/anthropic/conformance` | Synthetic Anthropic Messages and Claude usage fixtures and conformance cases |
|
|
54
|
+
| `@yolk-sdk/agent/providers/xai` | Grok subscription OAuth and token broker helpers |
|
|
55
|
+
| `@yolk-sdk/agent/providers/xai/grok` | Grok subscription request and auth helpers |
|
|
56
|
+
| `@yolk-sdk/agent/providers/xai/grok-provider` | Grok subscription LLM provider factory |
|
|
57
|
+
| `@yolk-sdk/agent/providers/xai/usage` | Grok subscription-allowance snapshots |
|
|
58
|
+
| `@yolk-sdk/agent/providers/xai/conformance` | Synthetic Grok Responses and Grok usage fixtures and conformance cases |
|
|
59
|
+
| `@yolk-sdk/agent/providers/subscription-usage` | Shared allowance snapshot and safe error schemas |
|
|
60
|
+
| `@yolk-sdk/agent/skillset` | Portable skill and slash-command parsing/catalogs |
|
|
61
|
+
| `@yolk-sdk/agent/voice` | Voice protocol, controller, tool handler, projection, speech |
|
|
62
|
+
| `@yolk-sdk/agent/voice/browser` | Browser WebRTC voice transport |
|
|
63
|
+
| `@yolk-sdk/agent/voice/react` | Headless browser voice React hook |
|
|
64
64
|
|
|
65
65
|
## Imports
|
|
66
66
|
|
|
@@ -297,6 +297,21 @@ configuration. Anthropic Claude forwards `low`, `medium`, `high`, and `xhigh` th
|
|
|
297
297
|
`output_config.effort`. It omits `minimal`, which Anthropic does not support. Hosts remain
|
|
298
298
|
responsible for choosing an effort accepted by the selected provider and model.
|
|
299
299
|
|
|
300
|
+
### Prompt caching
|
|
301
|
+
|
|
302
|
+
Provider prompt caching is always on (ADR 0008). Set `cacheKey` (for example the session id) on
|
|
303
|
+
`run` or `runRuntime` so providers route a conversation to its cached prefix: Anthropic gets
|
|
304
|
+
`cache_control` breakpoints and a Claude session header derived from the key, Codex and Grok `prompt_cache_key` plus their session headers, Vercel AI
|
|
305
|
+
Gateway `caching: 'auto'` and `x-session-affinity`, and OpenCode Go `x-opencode-session`. The
|
|
306
|
+
generic OpenAI-compatible chat provider sends nothing unless its config sets `cacheKeyHeaders`.
|
|
307
|
+
Claude entries last five minutes unless the provider sets `promptCacheTtl: '1h'`.
|
|
308
|
+
|
|
309
|
+
Keep the prefix byte-identical: per-request facts (fresh signed URLs, the current time) belong in
|
|
310
|
+
`LLMRequest.turnContext`, which adapters append after the conversation (Anthropic after every
|
|
311
|
+
breakpoint; Gateway's automatic markers still read the prefix before it). Loop hosts set it by
|
|
312
|
+
decorating `LLMProvider`. `LLMRequest.toolChoice: 'none'` forbids tool calls but keeps the tool
|
|
313
|
+
definitions; on Anthropic a changed `tool_choice` invalidates the cached messages.
|
|
314
|
+
|
|
300
315
|
### Anthropic tool schemas
|
|
301
316
|
|
|
302
317
|
Claude subscription OAuth rejects some valid JSON Schema constructs that Effect Schema can emit
|
|
@@ -416,6 +431,8 @@ policy and emits protocol-visible retry/error state:
|
|
|
416
431
|
[stream diagnostics guide](https://github.com/magoz/yolk-sdk/blob/main/apps/docs/content/docs/troubleshooting.mdx#diagnose-chat-stream-failures-with-stream-diagnostics).
|
|
417
432
|
- Chat Completions and Responses HTTP failures copy the envelope string `code` (falling back to
|
|
418
433
|
`type`) into `provider.providerCode`; free-text upstream bodies stay out of `LLMError`.
|
|
434
|
+
- Claude subscription (`anthropic_claude`) HTTP and stream errors use `error.details.error_code`
|
|
435
|
+
(for example `claude_code_version_too_old`), then `error.type`, then `error.code`.
|
|
419
436
|
- `AgentRetry.provider` exposes current retry metadata and chosen `delayMs`.
|
|
420
437
|
- `AgentError.provider` preserves final terminal metadata.
|
|
421
438
|
- `AgentErrorCode` includes `rate_limit`, `overloaded`, `context_overflow`, and generic
|
|
@@ -925,10 +942,15 @@ This package declares them; it does not run scripts.
|
|
|
925
942
|
|
|
926
943
|
- `makeTool({ output })` adds declaration-only `ToolDef.outputSchema`, lowered like `parameters`.
|
|
927
944
|
- `callableBy: 'all' | 'model' | 'codemode'` (default `all`) decides who may call a tool. For
|
|
928
|
-
`codemode` only, `discovery: 'listed' | 'search'` (default `listed`
|
|
945
|
+
`codemode` only, `discovery: 'listed' | 'search' | 'pinned'` (default `listed`; `pinned` is
|
|
946
|
+
always listed, outside the catalog budget) decides how scripts find it.
|
|
929
947
|
Codemode-only tools never reach providers. Approval, input, interaction, activated background,
|
|
930
948
|
`question`, `subagent`, and nested-access tools never run from code mode (stageable approval tools
|
|
931
|
-
are only staged; see Staged tool plans); `resolveTools` rejects `callableBy: 'codemode'` on them
|
|
949
|
+
are only staged; see Staged tool plans); `resolveTools` rejects `callableBy: 'codemode'` on them,
|
|
950
|
+
except a stageable approval tool, which may be stage-only: never declared, only `stage()`d from
|
|
951
|
+
scripts (see [ADR 0007](https://github.com/magoz/yolk-sdk/blob/main/docs/adr/0007-tool-exposure-and-catalog.md)).
|
|
952
|
+
- `instruct: ({ tools }) => RunInstruction` on a nested-access registration contributes a host
|
|
953
|
+
instruction (see Host instructions), collected in `ResolvedToolSet.instructions`.
|
|
932
954
|
- `nestedToolAccess: true` gives a registration's `execute` a `nested` executor over the other
|
|
933
955
|
code-mode-callable tools of the same resolution and host context. Nested calls run through the
|
|
934
956
|
resolved execute path and fail closed with model-visible error results. Assign nested call ids as
|
|
@@ -942,6 +964,48 @@ This package declares them; it does not run scripts.
|
|
|
942
964
|
Size the record with `makeNestedToolCallRecorder({ maxCalls })`; per-status `counts` cover
|
|
943
965
|
every call, dropped ones included.
|
|
944
966
|
|
|
967
|
+
## Deferred tools
|
|
968
|
+
|
|
969
|
+
`loading: 'deferred'` (on `makeTool`, `ToolDef`, or the MCP/connector `exposure` resolvers) keeps a
|
|
970
|
+
model-callable tool out of provider requests until the model loads it, so hosts can connect many
|
|
971
|
+
tools without spending context on them ([ADR 0007](https://github.com/magoz/yolk-sdk/blob/main/docs/adr/0007-tool-exposure-and-catalog.md)).
|
|
972
|
+
|
|
973
|
+
- When any tool is deferred, `resolveTools` adds the package `tool_search` tool (read access,
|
|
974
|
+
model-only; `makeToolSearchTool`). Its result names the tools it loaded; opt out with
|
|
975
|
+
`resolveTools(modules, context, { toolSearch: false })`, or register your own `tool_search`.
|
|
976
|
+
- Activation is derived from the transcript, never stored: each request declares
|
|
977
|
+
`declaredToolDefs(tools, messages)`, the eager tools plus deferred tools a `tool_search` result
|
|
978
|
+
activated, so replayed and resumed steps declare the same tools. Loading a tool changes the
|
|
979
|
+
declared tools, which start the request, so that request misses the prompt cache once; later
|
|
980
|
+
requests reuse the new prefix. Prefer code mode scripts for exploratory use.
|
|
981
|
+
- Deferral saves context; it is not authority. Approval-gated tools keep their approval when
|
|
982
|
+
deferred. `loading` on a `callableBy: 'codemode'` tool is a type error (`invalid_tool_exposure` at
|
|
983
|
+
resolution for raw definitions); `tool_search`, `question`, `subagent`, input, interaction, plan
|
|
984
|
+
review, background, and nested-access tools cannot be deferred (`deferred_unsupported_tool`).
|
|
985
|
+
|
|
986
|
+
## Host instructions
|
|
987
|
+
|
|
988
|
+
A `RunInstruction` (`{ key, state, render }`) is host context kept current in the conversation,
|
|
989
|
+
for example the code mode catalog (`ResolvedToolSet.instructions`). Pass it as
|
|
990
|
+
`RunConfig.instructions` or `RuntimeConfig.instructions`.
|
|
991
|
+
|
|
992
|
+
- Before each model request the loop compares `state` with the latest instruction message of the
|
|
993
|
+
same `key` and, only when it changed, appends a user-role message with `render(state)` and the
|
|
994
|
+
non-model-visible `instruction: { key, state }` envelope. Earlier messages never change, so a
|
|
995
|
+
changing instruction never invalidates the cached request prefix. `state: undefined` appends a
|
|
996
|
+
removal notice once.
|
|
997
|
+
- `render` gets only the current state: compaction keeps the latest message of each key
|
|
998
|
+
(`latestInstructionMessages`), so each one must stand alone.
|
|
999
|
+
- The appended messages join the run's created messages (persist them with the turn) but emit no
|
|
1000
|
+
`UserMessage` event. Durable hosts driving `runModelTurn` append and persist
|
|
1001
|
+
`instructionMessages(transcript, instructions)` before each step themselves; `runModelTurn` does
|
|
1002
|
+
not accept `instructions`.
|
|
1003
|
+
- Window compaction keeps instruction messages after its summary; custom compaction must keep
|
|
1004
|
+
`latestInstructionMessages(...)` too. Chat projections hide them (`isInstructionMessage`) and
|
|
1005
|
+
`toAgentMessages` round-trips them. Duplicate keys fail resolution (`duplicate_instruction`).
|
|
1006
|
+
- Hosts that cannot append messages to their conversation may put `render(state)` into the system
|
|
1007
|
+
prompt instead, only while `state` is defined (`undefined` renders the removal notice).
|
|
1008
|
+
|
|
945
1009
|
## Durable tool ledger
|
|
946
1010
|
|
|
947
1011
|
Steps that hosts re-execute (Vercel Workflow's queue is at-least-once) must not repeat writes.
|
|
@@ -1009,8 +1073,11 @@ aborts, and implementation bugs outside typed tool execution.
|
|
|
1009
1073
|
or step when call ids can repeat), keep its operations interruptible, and reserve about 15 s of
|
|
1010
1074
|
the step budget after `deadline` for recording outcomes.
|
|
1011
1075
|
- If you send `ToolDef`s to providers yourself (outside `run`/`runModelTurn`), filter them with
|
|
1012
|
-
protocol `
|
|
1013
|
-
|
|
1076
|
+
protocol `declaredToolDefs(tools, messages)`: codemode-only tools must never reach providers, and
|
|
1077
|
+
deferred tools only once a `tool_search` result activated them.
|
|
1078
|
+
- Durable hosts driving `runModelTurn` append and persist `instructionMessages(...)` before each
|
|
1079
|
+
model step (see Host instructions).
|
|
1080
|
+
- Executor decorators outside `ResolvedToolSet.execute` do not see nested code mode calls.
|
|
1014
1081
|
- Compact context and decide memory/search policy.
|
|
1015
1082
|
|
|
1016
1083
|
## Boundaries
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"window.d.mts","names":[],"sources":["../../src/compaction/window.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"window.d.mts","names":[],"sources":["../../src/compaction/window.ts"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { estimateAgentMessagesTokens } from "./estimator.mjs";
|
|
2
2
|
import { Data, Predicate } from "effect";
|
|
3
|
-
import { CompactionEnd, CompactionStart } from "@yolk-sdk/agent/protocol";
|
|
3
|
+
import { CompactionEnd, CompactionStart, isInstructionMessage, latestInstructionMessages } from "@yolk-sdk/agent/protocol";
|
|
4
4
|
//#region src/compaction/window.ts
|
|
5
5
|
const defaultCompactionTailMessageCount = 16;
|
|
6
6
|
const defaultMinimumCompactionMessages = 2;
|
|
@@ -51,7 +51,13 @@ const planWindowCompaction = (messages, options) => {
|
|
|
51
51
|
const applyCompactionPlan = (plan, options) => {
|
|
52
52
|
if (Predicate.isTagged(plan, "Skip")) return skippedCompactionResult(plan.reason, plan.messages, plan.beforeTokens);
|
|
53
53
|
const estimateTokens = estimator(options.estimateTokens);
|
|
54
|
-
const
|
|
54
|
+
const recentKeys = new Set(plan.recentMessages.flatMap((message) => isInstructionMessage(message) ? [message.instruction.key] : []));
|
|
55
|
+
const keptInstructions = latestInstructionMessages(plan.compactedMessages).filter((message) => !recentKeys.has(message.instruction.key));
|
|
56
|
+
const messages = [
|
|
57
|
+
options.summaryMessage,
|
|
58
|
+
...keptInstructions,
|
|
59
|
+
...plan.recentMessages
|
|
60
|
+
];
|
|
55
61
|
const afterTokens = estimateTokens(messages);
|
|
56
62
|
if (afterTokens >= plan.beforeTokens) return skippedCompactionResult("not_smaller", plan.messages, plan.beforeTokens);
|
|
57
63
|
return CompactionResult.Compacted({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"window.mjs","names":[],"sources":["../../src/compaction/window.ts"],"sourcesContent":["import {\n CompactionEnd,\n CompactionStart,\n type AgentEvent,\n type AgentMessage\n} from '@yolk-sdk/agent/protocol'\nimport { estimateAgentMessagesTokens, type TranscriptTokenEstimator } from './estimator.ts'\nimport { Data, Predicate } from 'effect'\n\nexport const defaultCompactionTailMessageCount = 16\n\nexport const defaultMinimumCompactionMessages = 2\n\nexport type CompactionSkipReason =\n | 'too_few_messages'\n | 'below_threshold'\n | 'empty_window'\n | 'not_smaller'\n\nexport type WindowCompactionPlanOptions = {\n readonly thresholdTokens: number\n readonly tailMessageCount?: number\n readonly minMessages?: number\n readonly estimateTokens?: TranscriptTokenEstimator\n}\n\nexport type WindowCompactionPlan = Data.TaggedEnum<{\n Skip: {\n readonly reason: CompactionSkipReason\n readonly messages: ReadonlyArray<AgentMessage>\n readonly beforeTokens: number\n }\n Compact: {\n readonly messages: ReadonlyArray<AgentMessage>\n readonly compactedMessages: ReadonlyArray<AgentMessage>\n readonly recentMessages: ReadonlyArray<AgentMessage>\n readonly tailStartIndex: number\n readonly beforeTokens: number\n }\n}>\n\nexport type SkippedCompactionPlan = Extract<WindowCompactionPlan, { readonly _tag: 'Skip' }>\n\nexport type CompactCompactionPlan = Extract<WindowCompactionPlan, { readonly _tag: 'Compact' }>\n\nconst WindowCompactionPlan = Data.taggedEnum<WindowCompactionPlan>()\n\nexport type CompactionResult = Data.TaggedEnum<{\n Skipped: {\n readonly reason: CompactionSkipReason\n readonly messages: ReadonlyArray<AgentMessage>\n readonly events: ReadonlyArray<AgentEvent>\n readonly beforeTokens: number\n }\n Compacted: {\n readonly strategy: string\n readonly messages: ReadonlyArray<AgentMessage>\n readonly events: ReadonlyArray<AgentEvent>\n readonly beforeTokens: number\n readonly afterTokens: number\n readonly compactedMessages: ReadonlyArray<AgentMessage>\n readonly recentMessages: ReadonlyArray<AgentMessage>\n readonly summaryMessage: AgentMessage\n }\n}>\n\nexport type SkippedCompactionResult = Extract<CompactionResult, { readonly _tag: 'Skipped' }>\n\nexport type CompletedCompactionResult = Extract<CompactionResult, { readonly _tag: 'Compacted' }>\n\nexport const CompactionResult = Data.taggedEnum<CompactionResult>()\n\nexport type ApplyCompactionPlanOptions = {\n readonly strategy: string\n readonly summaryMessage: AgentMessage\n readonly estimateTokens?: TranscriptTokenEstimator\n}\n\nconst estimator = (estimateTokens?: TranscriptTokenEstimator) =>\n estimateTokens ?? estimateAgentMessagesTokens\n\nconst skippedCompactionResult = (\n reason: CompactionSkipReason,\n messages: ReadonlyArray<AgentMessage>,\n beforeTokens: number\n): SkippedCompactionResult =>\n CompactionResult.Skipped({\n reason,\n messages,\n events: [],\n beforeTokens\n })\n\nexport const windowTailStartIndex = (\n messages: ReadonlyArray<AgentMessage>,\n tailMessageCount: number\n) => {\n const tailCount = Math.min(Math.max(0, tailMessageCount), Math.max(0, messages.length - 1))\n const initialIndex = Math.max(1, messages.length - tailCount)\n let index = initialIndex\n\n while (index > 1 && messages[index]?._tag === 'ToolResult') {\n index -= 1\n }\n\n return index\n}\n\nexport const planWindowCompaction = (\n messages: ReadonlyArray<AgentMessage>,\n options: WindowCompactionPlanOptions\n): WindowCompactionPlan => {\n const estimateTokens = estimator(options.estimateTokens)\n const beforeTokens = estimateTokens(messages)\n const minMessages = options.minMessages ?? defaultMinimumCompactionMessages\n\n if (messages.length <= minMessages) {\n return WindowCompactionPlan.Skip({\n reason: 'too_few_messages',\n messages,\n beforeTokens\n })\n }\n\n if (beforeTokens < options.thresholdTokens) {\n return WindowCompactionPlan.Skip({\n reason: 'below_threshold',\n messages,\n beforeTokens\n })\n }\n\n const tailStart = windowTailStartIndex(\n messages,\n options.tailMessageCount ?? defaultCompactionTailMessageCount\n )\n\n const compactedMessages = messages.slice(0, tailStart)\n const recentMessages = messages.slice(tailStart)\n\n if (compactedMessages.length === 0 || recentMessages.length === 0) {\n return WindowCompactionPlan.Skip({\n reason: 'empty_window',\n messages,\n beforeTokens\n })\n }\n\n return WindowCompactionPlan.Compact({\n messages,\n compactedMessages,\n recentMessages,\n tailStartIndex: tailStart,\n beforeTokens\n })\n}\n\nexport const applyCompactionPlan = (\n plan: WindowCompactionPlan,\n options: ApplyCompactionPlanOptions\n): CompactionResult => {\n if (Predicate.isTagged(plan, 'Skip')) {\n return skippedCompactionResult(plan.reason, plan.messages, plan.beforeTokens)\n }\n\n const estimateTokens = estimator(options.estimateTokens)\n const messages = [options.summaryMessage, ...plan.recentMessages]\n const afterTokens = estimateTokens(messages)\n\n if (afterTokens >= plan.beforeTokens) {\n return skippedCompactionResult('not_smaller', plan.messages, plan.beforeTokens)\n }\n\n return CompactionResult.Compacted({\n strategy: options.strategy,\n messages,\n events: [\n CompactionStart.make({ strategy: options.strategy }),\n CompactionEnd.make({\n strategy: options.strategy,\n beforeTokens: plan.beforeTokens,\n afterTokens\n })\n ],\n beforeTokens: plan.beforeTokens,\n afterTokens,\n compactedMessages: plan.compactedMessages,\n recentMessages: plan.recentMessages,\n summaryMessage: options.summaryMessage\n })\n}\n"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"window.mjs","names":[],"sources":["../../src/compaction/window.ts"],"sourcesContent":["import {\n CompactionEnd,\n CompactionStart,\n isInstructionMessage,\n latestInstructionMessages,\n type AgentEvent,\n type AgentMessage\n} from '@yolk-sdk/agent/protocol'\nimport { estimateAgentMessagesTokens, type TranscriptTokenEstimator } from './estimator.ts'\nimport { Data, Predicate } from 'effect'\n\nexport const defaultCompactionTailMessageCount = 16\n\nexport const defaultMinimumCompactionMessages = 2\n\nexport type CompactionSkipReason =\n | 'too_few_messages'\n | 'below_threshold'\n | 'empty_window'\n | 'not_smaller'\n\nexport type WindowCompactionPlanOptions = {\n readonly thresholdTokens: number\n readonly tailMessageCount?: number\n readonly minMessages?: number\n readonly estimateTokens?: TranscriptTokenEstimator\n}\n\nexport type WindowCompactionPlan = Data.TaggedEnum<{\n Skip: {\n readonly reason: CompactionSkipReason\n readonly messages: ReadonlyArray<AgentMessage>\n readonly beforeTokens: number\n }\n Compact: {\n readonly messages: ReadonlyArray<AgentMessage>\n readonly compactedMessages: ReadonlyArray<AgentMessage>\n readonly recentMessages: ReadonlyArray<AgentMessage>\n readonly tailStartIndex: number\n readonly beforeTokens: number\n }\n}>\n\nexport type SkippedCompactionPlan = Extract<WindowCompactionPlan, { readonly _tag: 'Skip' }>\n\nexport type CompactCompactionPlan = Extract<WindowCompactionPlan, { readonly _tag: 'Compact' }>\n\nconst WindowCompactionPlan = Data.taggedEnum<WindowCompactionPlan>()\n\nexport type CompactionResult = Data.TaggedEnum<{\n Skipped: {\n readonly reason: CompactionSkipReason\n readonly messages: ReadonlyArray<AgentMessage>\n readonly events: ReadonlyArray<AgentEvent>\n readonly beforeTokens: number\n }\n Compacted: {\n readonly strategy: string\n readonly messages: ReadonlyArray<AgentMessage>\n readonly events: ReadonlyArray<AgentEvent>\n readonly beforeTokens: number\n readonly afterTokens: number\n readonly compactedMessages: ReadonlyArray<AgentMessage>\n readonly recentMessages: ReadonlyArray<AgentMessage>\n readonly summaryMessage: AgentMessage\n }\n}>\n\nexport type SkippedCompactionResult = Extract<CompactionResult, { readonly _tag: 'Skipped' }>\n\nexport type CompletedCompactionResult = Extract<CompactionResult, { readonly _tag: 'Compacted' }>\n\nexport const CompactionResult = Data.taggedEnum<CompactionResult>()\n\nexport type ApplyCompactionPlanOptions = {\n readonly strategy: string\n readonly summaryMessage: AgentMessage\n readonly estimateTokens?: TranscriptTokenEstimator\n}\n\nconst estimator = (estimateTokens?: TranscriptTokenEstimator) =>\n estimateTokens ?? estimateAgentMessagesTokens\n\nconst skippedCompactionResult = (\n reason: CompactionSkipReason,\n messages: ReadonlyArray<AgentMessage>,\n beforeTokens: number\n): SkippedCompactionResult =>\n CompactionResult.Skipped({\n reason,\n messages,\n events: [],\n beforeTokens\n })\n\nexport const windowTailStartIndex = (\n messages: ReadonlyArray<AgentMessage>,\n tailMessageCount: number\n) => {\n const tailCount = Math.min(Math.max(0, tailMessageCount), Math.max(0, messages.length - 1))\n const initialIndex = Math.max(1, messages.length - tailCount)\n let index = initialIndex\n\n while (index > 1 && messages[index]?._tag === 'ToolResult') {\n index -= 1\n }\n\n return index\n}\n\nexport const planWindowCompaction = (\n messages: ReadonlyArray<AgentMessage>,\n options: WindowCompactionPlanOptions\n): WindowCompactionPlan => {\n const estimateTokens = estimator(options.estimateTokens)\n const beforeTokens = estimateTokens(messages)\n const minMessages = options.minMessages ?? defaultMinimumCompactionMessages\n\n if (messages.length <= minMessages) {\n return WindowCompactionPlan.Skip({\n reason: 'too_few_messages',\n messages,\n beforeTokens\n })\n }\n\n if (beforeTokens < options.thresholdTokens) {\n return WindowCompactionPlan.Skip({\n reason: 'below_threshold',\n messages,\n beforeTokens\n })\n }\n\n const tailStart = windowTailStartIndex(\n messages,\n options.tailMessageCount ?? defaultCompactionTailMessageCount\n )\n\n const compactedMessages = messages.slice(0, tailStart)\n const recentMessages = messages.slice(tailStart)\n\n if (compactedMessages.length === 0 || recentMessages.length === 0) {\n return WindowCompactionPlan.Skip({\n reason: 'empty_window',\n messages,\n beforeTokens\n })\n }\n\n return WindowCompactionPlan.Compact({\n messages,\n compactedMessages,\n recentMessages,\n tailStartIndex: tailStart,\n beforeTokens\n })\n}\n\nexport const applyCompactionPlan = (\n plan: WindowCompactionPlan,\n options: ApplyCompactionPlanOptions\n): CompactionResult => {\n if (Predicate.isTagged(plan, 'Skip')) {\n return skippedCompactionResult(plan.reason, plan.messages, plan.beforeTokens)\n }\n\n const estimateTokens = estimator(options.estimateTokens)\n\n // Host instructions (ADR 0007) the summary would fold away stay verbatim after it: the loop\n // compares instruction state with the uncompacted transcript and would never re-append them.\n const recentKeys = new Set(\n plan.recentMessages.flatMap(message =>\n isInstructionMessage(message) ? [message.instruction.key] : []\n )\n )\n\n const keptInstructions = latestInstructionMessages(plan.compactedMessages).filter(\n message => !recentKeys.has(message.instruction.key)\n )\n\n const messages = [options.summaryMessage, ...keptInstructions, ...plan.recentMessages]\n const afterTokens = estimateTokens(messages)\n\n if (afterTokens >= plan.beforeTokens) {\n return skippedCompactionResult('not_smaller', plan.messages, plan.beforeTokens)\n }\n\n return CompactionResult.Compacted({\n strategy: options.strategy,\n messages,\n events: [\n CompactionStart.make({ strategy: options.strategy }),\n CompactionEnd.make({\n strategy: options.strategy,\n beforeTokens: plan.beforeTokens,\n afterTokens\n })\n ],\n beforeTokens: plan.beforeTokens,\n afterTokens,\n compactedMessages: plan.compactedMessages,\n recentMessages: plan.recentMessages,\n summaryMessage: options.summaryMessage\n })\n}\n"],"mappings":";;;;AAWA,MAAa,oCAAoC;AAEjD,MAAa,mCAAmC;AAkChD,MAAM,uBAAuB,KAAK,WAAiC;AAyBnE,MAAa,mBAAmB,KAAK,WAA6B;AAQlE,MAAM,aAAa,mBACjB,kBAAkB;AAEpB,MAAM,2BACJ,QACA,UACA,iBAEA,iBAAiB,QAAQ;CACvB;CACA;CACA,QAAQ,CAAC;CACT;AACF,CAAC;AAEH,MAAa,wBACX,UACA,qBACG;CACH,MAAM,YAAY,KAAK,IAAI,KAAK,IAAI,GAAG,gBAAgB,GAAG,KAAK,IAAI,GAAG,SAAS,SAAS,CAAC,CAAC;CAE1F,IAAI,QADiB,KAAK,IAAI,GAAG,SAAS,SAAS,SAC5B;CAEvB,OAAO,QAAQ,KAAK,SAAS,QAAQ,SAAS,cAC5C,SAAS;CAGX,OAAO;AACT;AAEA,MAAa,wBACX,UACA,YACyB;CAEzB,MAAM,eADiB,UAAU,QAAQ,cACP,EAAE,QAAQ;CAC5C,MAAM,cAAc,QAAQ,eAAA;CAE5B,IAAI,SAAS,UAAU,aACrB,OAAO,qBAAqB,KAAK;EAC/B,QAAQ;EACR;EACA;CACF,CAAC;CAGH,IAAI,eAAe,QAAQ,iBACzB,OAAO,qBAAqB,KAAK;EAC/B,QAAQ;EACR;EACA;CACF,CAAC;CAGH,MAAM,YAAY,qBAChB,UACA,QAAQ,oBAAA,EACV;CAEA,MAAM,oBAAoB,SAAS,MAAM,GAAG,SAAS;CACrD,MAAM,iBAAiB,SAAS,MAAM,SAAS;CAE/C,IAAI,kBAAkB,WAAW,KAAK,eAAe,WAAW,GAC9D,OAAO,qBAAqB,KAAK;EAC/B,QAAQ;EACR;EACA;CACF,CAAC;CAGH,OAAO,qBAAqB,QAAQ;EAClC;EACA;EACA;EACA,gBAAgB;EAChB;CACF,CAAC;AACH;AAEA,MAAa,uBACX,MACA,YACqB;CACrB,IAAI,UAAU,SAAS,MAAM,MAAM,GACjC,OAAO,wBAAwB,KAAK,QAAQ,KAAK,UAAU,KAAK,YAAY;CAG9E,MAAM,iBAAiB,UAAU,QAAQ,cAAc;CAIvD,MAAM,aAAa,IAAI,IACrB,KAAK,eAAe,SAAQ,YAC1B,qBAAqB,OAAO,IAAI,CAAC,QAAQ,YAAY,GAAG,IAAI,CAAC,CAC/D,CACF;CAEA,MAAM,mBAAmB,0BAA0B,KAAK,iBAAiB,EAAE,QACzE,YAAW,CAAC,WAAW,IAAI,QAAQ,YAAY,GAAG,CACpD;CAEA,MAAM,WAAW;EAAC,QAAQ;EAAgB,GAAG;EAAkB,GAAG,KAAK;CAAc;CACrF,MAAM,cAAc,eAAe,QAAQ;CAE3C,IAAI,eAAe,KAAK,cACtB,OAAO,wBAAwB,eAAe,KAAK,UAAU,KAAK,YAAY;CAGhF,OAAO,iBAAiB,UAAU;EAChC,UAAU,QAAQ;EAClB;EACA,QAAQ,CACN,gBAAgB,KAAK,EAAE,UAAU,QAAQ,SAAS,CAAC,GACnD,cAAc,KAAK;GACjB,UAAU,QAAQ;GAClB,cAAc,KAAK;GACnB;EACF,CAAC,CACH;EACA,cAAc,KAAK;EACnB;EACA,mBAAmB,KAAK;EACxB,gBAAgB,KAAK;EACrB,gBAAgB,QAAQ;CAC1B,CAAC;AACH"}
|
package/dist/loop/index.d.mts
CHANGED
|
@@ -7,5 +7,6 @@ import { LLMProvider, LLMRequest } from "./services/llm-provider.mjs";
|
|
|
7
7
|
import { LoopConfig, LoopConfigSettings } from "./services/loop-config.mjs";
|
|
8
8
|
import { ToolExecutionOptions, ToolExecutor } from "./services/tool-executor.mjs";
|
|
9
9
|
import { decorateLLMProvider, makeAgentLoopLayer } from "./layer.mjs";
|
|
10
|
+
import { RunInstruction, instructionMessages } from "./instructions.mjs";
|
|
10
11
|
import { AgentLoopRunId, ModelTurnConfig, PreparedToolBatch, RunConfig, ToolBatchConfig, loadInteractionReceipts, prepareToolBatch, run, runModelTurn, runToolBatch } from "./run.mjs";
|
|
11
|
-
export { AbortError, type AgentLoopError, type AgentLoopRunId, type CollectModelTurnAttemptResult, ContextTransformError, type ContextTransformResult, ContextTransformer, FauxExhaustedError, LLMDone, LLMError, LLMEvent, LLMProvider, type LLMProviderError, LLMProviderToolResult, LLMReasoningDelta, type LLMRequest, LLMResponseIssue, LLMTextDelta, LLMToolCall, LLMToolInputDelta, LLMToolInputStart, LLMUsage, LoopConfig, type LoopConfigSettings, type ModelTurnCollection, type ModelTurnConfig, type ModelTurnResult, type PreparedToolBatch, type RunConfig, type ToolBatchConfig, ToolError, type ToolExecutionOptions, ToolExecutor, accumulateAssistantMessage, agentLoopErrorToAgentError, collectModelTurn, collectModelTurnAttempt, collectReasoning, collectText, collectToolCalls, decorateLLMProvider, loadInteractionReceipts, makeAgentLoopLayer, prepareToolBatch, run, runModelTurn, runToolBatch };
|
|
12
|
+
export { AbortError, type AgentLoopError, type AgentLoopRunId, type CollectModelTurnAttemptResult, ContextTransformError, type ContextTransformResult, ContextTransformer, FauxExhaustedError, LLMDone, LLMError, LLMEvent, LLMProvider, type LLMProviderError, LLMProviderToolResult, LLMReasoningDelta, type LLMRequest, LLMResponseIssue, LLMTextDelta, LLMToolCall, LLMToolInputDelta, LLMToolInputStart, LLMUsage, LoopConfig, type LoopConfigSettings, type ModelTurnCollection, type ModelTurnConfig, type ModelTurnResult, type PreparedToolBatch, type RunConfig, type RunInstruction, type ToolBatchConfig, ToolError, type ToolExecutionOptions, ToolExecutor, accumulateAssistantMessage, agentLoopErrorToAgentError, collectModelTurn, collectModelTurnAttempt, collectReasoning, collectText, collectToolCalls, decorateLLMProvider, instructionMessages, loadInteractionReceipts, makeAgentLoopLayer, prepareToolBatch, run, runModelTurn, runToolBatch };
|
package/dist/loop/index.mjs
CHANGED
|
@@ -7,5 +7,6 @@ import { LLMProvider } from "./services/llm-provider.mjs";
|
|
|
7
7
|
import { LoopConfig } from "./services/loop-config.mjs";
|
|
8
8
|
import { ToolExecutor } from "./services/tool-executor.mjs";
|
|
9
9
|
import { decorateLLMProvider, makeAgentLoopLayer } from "./layer.mjs";
|
|
10
|
+
import { instructionMessages } from "./instructions.mjs";
|
|
10
11
|
import { loadInteractionReceipts, prepareToolBatch, run, runModelTurn, runToolBatch } from "./run.mjs";
|
|
11
|
-
export { AbortError, ContextTransformError, ContextTransformer, FauxExhaustedError, LLMDone, LLMError, LLMEvent, LLMProvider, LLMProviderToolResult, LLMReasoningDelta, LLMResponseIssue, LLMTextDelta, LLMToolCall, LLMToolInputDelta, LLMToolInputStart, LLMUsage, LoopConfig, ToolError, ToolExecutor, accumulateAssistantMessage, agentLoopErrorToAgentError, collectModelTurn, collectModelTurnAttempt, collectReasoning, collectText, collectToolCalls, decorateLLMProvider, loadInteractionReceipts, makeAgentLoopLayer, prepareToolBatch, run, runModelTurn, runToolBatch };
|
|
12
|
+
export { AbortError, ContextTransformError, ContextTransformer, FauxExhaustedError, LLMDone, LLMError, LLMEvent, LLMProvider, LLMProviderToolResult, LLMReasoningDelta, LLMResponseIssue, LLMTextDelta, LLMToolCall, LLMToolInputDelta, LLMToolInputStart, LLMUsage, LoopConfig, ToolError, ToolExecutor, accumulateAssistantMessage, agentLoopErrorToAgentError, collectModelTurn, collectModelTurnAttempt, collectReasoning, collectText, collectToolCalls, decorateLLMProvider, instructionMessages, loadInteractionReceipts, makeAgentLoopLayer, prepareToolBatch, run, runModelTurn, runToolBatch };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as Schema from "effect/Schema";
|
|
2
|
+
import { AgentMessage, UserMessage } from "@yolk-sdk/agent/protocol";
|
|
3
|
+
|
|
4
|
+
//#region src/loop/instructions.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* A host instruction kept current in the conversation (ADR 0007), for example the code mode tool
|
|
7
|
+
* catalog. Before each model request the loop compares `state` with the state of the latest
|
|
8
|
+
* instruction message with the same `key` in the transcript; only when they differ it appends one
|
|
9
|
+
* user-role instruction message whose content is `render(current)`. Earlier messages never change,
|
|
10
|
+
* so a changing instruction never rewrites the cached request prefix, and a redelivered step
|
|
11
|
+
* decides the same from the same transcript.
|
|
12
|
+
*/
|
|
13
|
+
type RunInstruction = {
|
|
14
|
+
readonly key: string; /** The current state; `undefined` when the instruction no longer applies. */
|
|
15
|
+
readonly state: Schema.Json | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* The model-visible text of a state, or a removal notice (`undefined`). Self-contained: it never
|
|
18
|
+
* sees the previous state, because compaction keeps only the latest message of each key
|
|
19
|
+
* (`latestInstructionMessages`), so that message alone must carry the whole instruction.
|
|
20
|
+
*/
|
|
21
|
+
readonly render: (current: Schema.Json | undefined) => string;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* The instruction messages a model request needs before it runs, in `instructions` order. States
|
|
25
|
+
* compare as JSON values, independent of object key order. A removal is recorded once as an
|
|
26
|
+
* instruction message without a state.
|
|
27
|
+
*/
|
|
28
|
+
declare const instructionMessages: (messages: ReadonlyArray<AgentMessage>, instructions: ReadonlyArray<RunInstruction>) => ReadonlyArray<UserMessage>;
|
|
29
|
+
/**
|
|
30
|
+
* The instruction messages a request needs, appended. They join the run's created messages (so
|
|
31
|
+
* hosts persist them with the turn) but emit no `UserMessage` event: they are not user input.
|
|
32
|
+
*/
|
|
33
|
+
declare const withInstructionMessages: (messages: ReadonlyArray<AgentMessage>, instructions: ReadonlyArray<RunInstruction> | undefined) => {
|
|
34
|
+
messages: readonly (UserMessage | import("@yolk-sdk/agent/protocol").AssistantAgentMessage | import("@yolk-sdk/agent/protocol").ToolResultMessage)[];
|
|
35
|
+
appended: readonly UserMessage[];
|
|
36
|
+
};
|
|
37
|
+
//#endregion
|
|
38
|
+
export { RunInstruction, instructionMessages, withInstructionMessages };
|
|
39
|
+
//# sourceMappingURL=instructions.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instructions.d.mts","names":[],"sources":["../../src/loop/instructions.ts"],"mappings":";;;;;;AAgBA;;;;;;KAAY,cAAA;EAAA,SACD,GAAA,UAQA;EAAA,SANA,KAAA,EAAO,MAAA,CAAO,IAAA;EAMW;;;AAAgB;AAQpD;EARoC,SAAzB,MAAA,GAAS,OAAA,EAAS,MAAA,CAAO,IAAI;AAAA;;;;;;cAQ3B,mBAAA,GACX,QAAA,EAAU,aAAA,CAAc,YAAA,GACxB,YAAA,EAAc,aAAA,CAAc,cAAA,MAC3B,aAAA,CAAc,WAAA;;;;;cA6BJ,uBAAA,GACX,QAAA,EAAU,aAAA,CAAc,YAAA,GACxB,YAAA,EAAc,aAAA,CAAc,cAAA"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { UserMessage, interactionJsonEquals, latestInstructionState } from "@yolk-sdk/agent/protocol";
|
|
2
|
+
//#region src/loop/instructions.ts
|
|
3
|
+
/**
|
|
4
|
+
* The instruction messages a model request needs before it runs, in `instructions` order. States
|
|
5
|
+
* compare as JSON values, independent of object key order. A removal is recorded once as an
|
|
6
|
+
* instruction message without a state.
|
|
7
|
+
*/
|
|
8
|
+
const instructionMessages = (messages, instructions) => instructions.flatMap((instruction) => {
|
|
9
|
+
const previous = latestInstructionState(messages, instruction.key);
|
|
10
|
+
const current = instruction.state;
|
|
11
|
+
if (current === void 0) {
|
|
12
|
+
if (previous === void 0) return [];
|
|
13
|
+
return [UserMessage.make({
|
|
14
|
+
content: instruction.render(void 0),
|
|
15
|
+
instruction: { key: instruction.key }
|
|
16
|
+
})];
|
|
17
|
+
}
|
|
18
|
+
if (previous !== void 0 && interactionJsonEquals(previous, current)) return [];
|
|
19
|
+
const content = instruction.render(current);
|
|
20
|
+
return content.trim().length === 0 ? [] : [UserMessage.make({
|
|
21
|
+
content,
|
|
22
|
+
instruction: {
|
|
23
|
+
key: instruction.key,
|
|
24
|
+
state: current
|
|
25
|
+
}
|
|
26
|
+
})];
|
|
27
|
+
});
|
|
28
|
+
/**
|
|
29
|
+
* The instruction messages a request needs, appended. They join the run's created messages (so
|
|
30
|
+
* hosts persist them with the turn) but emit no `UserMessage` event: they are not user input.
|
|
31
|
+
*/
|
|
32
|
+
const withInstructionMessages = (messages, instructions) => {
|
|
33
|
+
const appended = instructions === void 0 || instructions.length === 0 ? [] : instructionMessages(messages, instructions);
|
|
34
|
+
return {
|
|
35
|
+
messages: appended.length === 0 ? messages : [...messages, ...appended],
|
|
36
|
+
appended
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
//#endregion
|
|
40
|
+
export { instructionMessages, withInstructionMessages };
|
|
41
|
+
|
|
42
|
+
//# sourceMappingURL=instructions.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instructions.mjs","names":[],"sources":["../../src/loop/instructions.ts"],"sourcesContent":["import type * as Schema from 'effect/Schema'\nimport {\n interactionJsonEquals,\n latestInstructionState,\n UserMessage,\n type AgentMessage\n} from '@yolk-sdk/agent/protocol'\n\n/**\n * A host instruction kept current in the conversation (ADR 0007), for example the code mode tool\n * catalog. Before each model request the loop compares `state` with the state of the latest\n * instruction message with the same `key` in the transcript; only when they differ it appends one\n * user-role instruction message whose content is `render(current)`. Earlier messages never change,\n * so a changing instruction never rewrites the cached request prefix, and a redelivered step\n * decides the same from the same transcript.\n */\nexport type RunInstruction = {\n readonly key: string\n /** The current state; `undefined` when the instruction no longer applies. */\n readonly state: Schema.Json | undefined\n /**\n * The model-visible text of a state, or a removal notice (`undefined`). Self-contained: it never\n * sees the previous state, because compaction keeps only the latest message of each key\n * (`latestInstructionMessages`), so that message alone must carry the whole instruction.\n */\n readonly render: (current: Schema.Json | undefined) => string\n}\n\n/**\n * The instruction messages a model request needs before it runs, in `instructions` order. States\n * compare as JSON values, independent of object key order. A removal is recorded once as an\n * instruction message without a state.\n */\nexport const instructionMessages = (\n messages: ReadonlyArray<AgentMessage>,\n instructions: ReadonlyArray<RunInstruction>\n): ReadonlyArray<UserMessage> =>\n instructions.flatMap(instruction => {\n const previous = latestInstructionState(messages, instruction.key)\n const current = instruction.state\n\n if (current === undefined) {\n if (previous === undefined) return []\n\n return [\n UserMessage.make({\n content: instruction.render(undefined),\n instruction: { key: instruction.key }\n })\n ]\n }\n\n if (previous !== undefined && interactionJsonEquals(previous, current)) return []\n\n const content = instruction.render(current)\n\n return content.trim().length === 0\n ? []\n : [UserMessage.make({ content, instruction: { key: instruction.key, state: current } })]\n })\n\n/**\n * The instruction messages a request needs, appended. They join the run's created messages (so\n * hosts persist them with the turn) but emit no `UserMessage` event: they are not user input.\n */\nexport const withInstructionMessages = (\n messages: ReadonlyArray<AgentMessage>,\n instructions: ReadonlyArray<RunInstruction> | undefined\n) => {\n const appended =\n instructions === undefined || instructions.length === 0\n ? []\n : instructionMessages(messages, instructions)\n\n return { messages: appended.length === 0 ? messages : [...messages, ...appended], appended }\n}\n"],"mappings":";;;;;;;AAiCA,MAAa,uBACX,UACA,iBAEA,aAAa,SAAQ,gBAAe;CAClC,MAAM,WAAW,uBAAuB,UAAU,YAAY,GAAG;CACjE,MAAM,UAAU,YAAY;CAE5B,IAAI,YAAY,KAAA,GAAW;EACzB,IAAI,aAAa,KAAA,GAAW,OAAO,CAAC;EAEpC,OAAO,CACL,YAAY,KAAK;GACf,SAAS,YAAY,OAAO,KAAA,CAAS;GACrC,aAAa,EAAE,KAAK,YAAY,IAAI;EACtC,CAAC,CACH;CACF;CAEA,IAAI,aAAa,KAAA,KAAa,sBAAsB,UAAU,OAAO,GAAG,OAAO,CAAC;CAEhF,MAAM,UAAU,YAAY,OAAO,OAAO;CAE1C,OAAO,QAAQ,KAAK,EAAE,WAAW,IAC7B,CAAC,IACD,CAAC,YAAY,KAAK;EAAE;EAAS,aAAa;GAAE,KAAK,YAAY;GAAK,OAAO;EAAQ;CAAE,CAAC,CAAC;AAC3F,CAAC;;;;;AAMH,MAAa,2BACX,UACA,iBACG;CACH,MAAM,WACJ,iBAAiB,KAAA,KAAa,aAAa,WAAW,IAClD,CAAC,IACD,oBAAoB,UAAU,YAAY;CAEhD,OAAO;EAAE,UAAU,SAAS,WAAW,IAAI,WAAW,CAAC,GAAG,UAAU,GAAG,QAAQ;EAAG;CAAS;AAC7F"}
|
package/dist/loop/run.d.mts
CHANGED
|
@@ -3,6 +3,7 @@ import { ContextTransformer } from "./services/context-transformer.mjs";
|
|
|
3
3
|
import { LLMProvider } from "./services/llm-provider.mjs";
|
|
4
4
|
import { LoopConfig } from "./services/loop-config.mjs";
|
|
5
5
|
import { ToolExecutor } from "./services/tool-executor.mjs";
|
|
6
|
+
import { RunInstruction } from "./instructions.mjs";
|
|
6
7
|
import { Effect, Stream } from "effect";
|
|
7
8
|
import { AgentEvent, AgentMessage, AgentModelCapabilities, AgentReasoningEffort, AgentUsage, HitlRequest, HitlResponse, InputToolHandler, InteractionHost, InteractionPreflight, InteractionReceipt, InteractionRef, ToolApprovalPreviewer, ToolCall, ToolDef } from "@yolk-sdk/agent/protocol";
|
|
8
9
|
|
|
@@ -12,6 +13,11 @@ type RunConfig = {
|
|
|
12
13
|
readonly messages: ReadonlyArray<AgentMessage>;
|
|
13
14
|
readonly systemPrompt: string;
|
|
14
15
|
readonly tools: ReadonlyArray<ToolDef>;
|
|
16
|
+
/** Host instructions kept current in the conversation (ADR 0007), for example
|
|
17
|
+
* `ResolvedToolSet.instructions`: before each model request a changed one is appended as a
|
|
18
|
+
* user-role instruction message, never rewriting earlier messages.
|
|
19
|
+
*/
|
|
20
|
+
readonly instructions?: ReadonlyArray<RunInstruction>;
|
|
15
21
|
readonly hitlResponses?: ReadonlyArray<HitlResponse>; /** Server-side input validators by tool name (from ResolvedToolSet.inputs). */
|
|
16
22
|
readonly inputs?: Readonly<Record<string, InputToolHandler>>;
|
|
17
23
|
/** Server-side interaction preflight by tool name (from ResolvedToolSet.interactions).
|
|
@@ -35,9 +41,16 @@ type RunConfig = {
|
|
|
35
41
|
readonly resume?: boolean;
|
|
36
42
|
readonly model: string;
|
|
37
43
|
readonly reasoningEffort?: AgentReasoningEffort;
|
|
38
|
-
readonly capabilities?: AgentModelCapabilities;
|
|
44
|
+
readonly capabilities?: AgentModelCapabilities; /** Forwarded as `LLMRequest.cacheKey` on every model request of this run. */
|
|
45
|
+
readonly cacheKey?: string;
|
|
39
46
|
};
|
|
40
|
-
|
|
47
|
+
/**
|
|
48
|
+
* One model step for durable hosts. They append and persist `instructionMessages(...)` before
|
|
49
|
+
* the step themselves (ADR 0007), so `instructions` is not accepted here: a step cannot report
|
|
50
|
+
* messages it appended, and they would be re-appended, unpersisted, on every step.
|
|
51
|
+
*/
|
|
52
|
+
type ModelTurnConfig = Omit<RunConfig, 'instructions'> & {
|
|
53
|
+
readonly instructions?: never;
|
|
41
54
|
readonly turn: number;
|
|
42
55
|
};
|
|
43
56
|
type ToolBatchConfig = {
|
package/dist/loop/run.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.d.mts","names":[],"sources":["../../src/loop/run.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"run.d.mts","names":[],"sources":["../../src/loop/run.ts"],"mappings":"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"}
|
package/dist/loop/run.mjs
CHANGED
|
@@ -4,13 +4,14 @@ import { ContextTransformer } from "./services/context-transformer.mjs";
|
|
|
4
4
|
import { LLMProvider } from "./services/llm-provider.mjs";
|
|
5
5
|
import { LoopConfig } from "./services/loop-config.mjs";
|
|
6
6
|
import { ToolExecutor, unavailableToolExecutor } from "./services/tool-executor.mjs";
|
|
7
|
+
import { withInstructionMessages } from "./instructions.mjs";
|
|
7
8
|
import "../protocol/change-preview.mjs";
|
|
8
9
|
import { truncateCodePoints } from "../protocol/bounded-text.mjs";
|
|
9
10
|
import { validInteractionReceipt as validInteractionReceipt$1 } from "../protocol/tool.mjs";
|
|
10
11
|
import { withToolArgumentsErrorHint } from "../protocol/tool-argument-hints.mjs";
|
|
11
12
|
import { Array as Array$1, Clock, Data, Effect, Match, Option, Predicate, Ref, Stream, Struct } from "effect";
|
|
12
13
|
import * as Schema$1 from "effect/Schema";
|
|
13
|
-
import { AgentAwaitingInput, AgentEnd, AgentRetry, AgentStart, AssistantMessageEvent, InputRequest, InputRequested, InteractionRequest, InteractionRequested, InteractionResponse, LLMReasoningDelta, LLMStreamEnd, LLMStreamStart, LLMTextDelta, ProviderToolResult, QuestionRequest, QuestionRequested, QuestionToolParams, SubagentCompleted, SubagentStarted, ToolApprovalRequest, ToolApprovalRequested, ToolExecutionAccepted, ToolExecutionCompleted, ToolExecutionError, ToolExecutionStarted, ToolInputDelta, ToolInputEnd, ToolInputStart, ToolResult, TurnEnd, TurnStart, UsageUpdate, addAgentUsage, assistantHostToolCalls, contentParts, contentPreview, decodeBackgroundToolInput, formatInputResponseContent, formatQuestionResponseContent, hitlResponseEvent, inputRequestId, inputResponseStructuredContent, interactionRequestId, makeSubagentRunId, providerToolDefs, questionResponseStructuredContent, toolResultMessageFromResult, zeroAgentUsage } from "@yolk-sdk/agent/protocol";
|
|
14
|
+
import { AgentAwaitingInput, AgentEnd, AgentRetry, AgentStart, AssistantMessageEvent, InputRequest, InputRequested, InteractionRequest, InteractionRequested, InteractionResponse, LLMReasoningDelta, LLMStreamEnd, LLMStreamStart, LLMTextDelta, ProviderToolResult, QuestionRequest, QuestionRequested, QuestionToolParams, SubagentCompleted, SubagentStarted, ToolApprovalRequest, ToolApprovalRequested, ToolExecutionAccepted, ToolExecutionCompleted, ToolExecutionError, ToolExecutionStarted, ToolInputDelta, ToolInputEnd, ToolInputStart, ToolResult, TurnEnd, TurnStart, UsageUpdate, addAgentUsage, assistantHostToolCalls, contentParts, contentPreview, declaredToolDefs, decodeBackgroundToolInput, formatInputResponseContent, formatQuestionResponseContent, hitlResponseEvent, inputRequestId, inputResponseStructuredContent, interactionRequestId, makeSubagentRunId, providerToolDefs, questionResponseStructuredContent, toolResultMessageFromResult, zeroAgentUsage } from "@yolk-sdk/agent/protocol";
|
|
14
15
|
//#region src/loop/run.ts
|
|
15
16
|
const objectField = (input, key) => {
|
|
16
17
|
if (!Predicate.isObjectOrArray(input)) return;
|
|
@@ -783,14 +784,23 @@ const makeModelOnlyAfterLlmStream = (input, llmEventsRef) => Stream.unwrap(Effec
|
|
|
783
784
|
})
|
|
784
785
|
]);
|
|
785
786
|
}));
|
|
787
|
+
/**
|
|
788
|
+
* One provider request. `transcript` is the full conversation before any context transform:
|
|
789
|
+
* deferred tools activated by `tool_search` results in it are declared (ADR 0007).
|
|
790
|
+
*/
|
|
791
|
+
const providerRequest = (config, messages, transcript) => {
|
|
792
|
+
const request = {
|
|
793
|
+
messages,
|
|
794
|
+
tools: declaredToolDefs(config.tools, transcript),
|
|
795
|
+
model: config.model,
|
|
796
|
+
reasoningEffort: config.reasoningEffort,
|
|
797
|
+
systemPrompt: config.systemPrompt
|
|
798
|
+
};
|
|
799
|
+
if (config.cacheKey !== void 0) request.cacheKey = config.cacheKey;
|
|
800
|
+
return request;
|
|
801
|
+
};
|
|
786
802
|
const makeLlmStream = (input, llmEvents, result) => {
|
|
787
|
-
const makeStream = () => input.provider.stream(
|
|
788
|
-
messages: result.messages,
|
|
789
|
-
tools: providerToolDefs(input.config.tools),
|
|
790
|
-
model: input.config.model,
|
|
791
|
-
reasoningEffort: input.config.reasoningEffort,
|
|
792
|
-
systemPrompt: input.config.systemPrompt
|
|
793
|
-
});
|
|
803
|
+
const makeStream = () => input.provider.stream(providerRequest(input.config, result.messages, input.currentMessages));
|
|
794
804
|
return Stream.fromIterable(result.events).pipe(Stream.concat(withProviderRetries(makeStream(), input.loopConfig, makeStream, 1))).pipe(Stream.tap((event) => {
|
|
795
805
|
if (!isLlmEvent(event)) return Effect.void;
|
|
796
806
|
const appendEvent = Ref.update(llmEvents, (events) => [...events, event]);
|
|
@@ -799,13 +809,7 @@ const makeLlmStream = (input, llmEvents, result) => {
|
|
|
799
809
|
}), Stream.flatMap((event) => Predicate.isTagged(event, "AgentRetry") ? Stream.make(event) : isLlmEvent(event) ? Stream.fromIterable(toLlmEvent(event)) : Stream.make(event)), Stream.concat(makeAfterLlmStream(input, llmEvents)));
|
|
800
810
|
};
|
|
801
811
|
const makeModelOnlyLlmStream = (input, llmEvents, result) => {
|
|
802
|
-
const makeStream = () => input.provider.stream(
|
|
803
|
-
messages: result.messages,
|
|
804
|
-
tools: providerToolDefs(input.config.tools),
|
|
805
|
-
model: input.config.model,
|
|
806
|
-
reasoningEffort: input.config.reasoningEffort,
|
|
807
|
-
systemPrompt: input.config.systemPrompt
|
|
808
|
-
});
|
|
812
|
+
const makeStream = () => input.provider.stream(providerRequest(input.config, result.messages, input.currentMessages));
|
|
809
813
|
return Stream.fromIterable(result.events).pipe(Stream.concat(withProviderRetries(makeStream(), input.loopConfig, makeStream, 1))).pipe(Stream.tap((event) => {
|
|
810
814
|
if (!isLlmEvent(event)) return Effect.void;
|
|
811
815
|
const appendEvent = Ref.update(llmEvents, (events) => [...events, event]);
|
|
@@ -822,13 +826,27 @@ const withoutConsumedAnswers = (config) => Struct.omit(config, [
|
|
|
822
826
|
"awaitingRequests",
|
|
823
827
|
"resume"
|
|
824
828
|
]);
|
|
829
|
+
/**
|
|
830
|
+
* Appends the instruction messages this model request needs (ADR 0007) to the turn's messages and
|
|
831
|
+
* to the run's created messages, so later turns and the host's persisted transcript see them.
|
|
832
|
+
*/
|
|
833
|
+
const withTurnInstructions = (input) => Effect.gen(function* () {
|
|
834
|
+
const { messages, appended } = withInstructionMessages(input.currentMessages, input.config.instructions);
|
|
835
|
+
if (appended.length === 0) return input;
|
|
836
|
+
yield* Ref.update(input.createdMessages, (created) => [...created, ...appended]);
|
|
837
|
+
return {
|
|
838
|
+
...input,
|
|
839
|
+
currentMessages: messages
|
|
840
|
+
};
|
|
841
|
+
});
|
|
825
842
|
const makeTurnStream = (input) => Stream.suspend(() => {
|
|
826
843
|
if (input.turn > input.loopConfig.maxTurns) return Stream.fail(new AbortError({ reason: "max_turns" }));
|
|
827
844
|
const llmStream = Stream.unwrap(Effect.gen(function* () {
|
|
828
845
|
const llmEvents = yield* Ref.make([]);
|
|
829
|
-
const
|
|
846
|
+
const instructed = yield* withTurnInstructions(input);
|
|
847
|
+
const result = yield* input.contextTransformer.transform(instructed.currentMessages);
|
|
830
848
|
yield* validateCapabilities(input.config, result.messages);
|
|
831
|
-
return makeLlmStream(
|
|
849
|
+
return makeLlmStream(instructed, llmEvents, result);
|
|
832
850
|
}));
|
|
833
851
|
return Stream.fromIterable([TurnStart.make({ turn: input.turn }), LLMStreamStart.make({ turn: input.turn })]).pipe(Stream.concat(llmStream));
|
|
834
852
|
});
|