mixdog 1.3.0 → 1.3.1
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/NOTICE.md +52 -9
- package/package.json +1 -1
- package/src/defaults/shipped-history.json +4 -1
- package/src/defaults/skills/setup/references/actions.md +4 -1
- package/src/defaults/skills/setup-guide/SKILL.md +10 -7
- package/src/output-styles/common.md +13 -8
- package/src/rules/agent-mode/AGENT_MODE.md +1 -1
- package/src/rules/agent-mode/MIXY.md +11 -4
- package/src/runtime/agent/orchestrator/context/role-instructions.mjs +72 -14
- package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +7 -2
- package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +7 -8
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/lib/tool-call-wire-ids.mjs +65 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +8 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +9 -2
- package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +14 -2
- package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +17 -0
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +4 -2
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +14 -4
- package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +37 -7
- package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +5 -3
- package/src/runtime/agent/orchestrator/session/agent-room.d.mts +4 -0
- package/src/runtime/agent/orchestrator/session/agent-room.mjs +17 -8
- package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +32 -5
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +9 -0
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +108 -6
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +8 -14
- package/src/runtime/agent/orchestrator/session/loop/usage.mjs +46 -4
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +18 -8
- package/src/runtime/agent/orchestrator/session/manager/provider-replay.mjs +50 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +7 -20
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +7 -1
- package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/mixy-name.mjs +5 -2
- package/src/runtime/agent/orchestrator/session/routine-result.d.mts +17 -1
- package/src/runtime/agent/orchestrator/session/routine-result.mjs +61 -9
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +14 -9
- package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +92 -15
- package/src/runtime/attachments/store.mjs +6 -0
- package/src/runtime/effort-judge/judge-client.mjs +1 -1
- package/src/runtime/effort-judge/model-manifest.json +7 -7
- package/src/runtime/shared/agent-kind.mjs +152 -0
- package/src/runtime/shared/agent-route-config.d.mts +1 -0
- package/src/runtime/shared/agent-route-config.mjs +22 -8
- package/src/runtime/shared/agent-store.mjs +132 -0
- package/src/runtime/shared/bot-split-migration.mjs +457 -0
- package/src/runtime/shared/config-patch.mjs +20 -1
- package/src/runtime/shared/connector-catalog.d.mts +1 -2
- package/src/runtime/shared/connector-catalog.mjs +2 -4
- package/src/runtime/shared/connector-triggers.mjs +2 -0
- package/src/runtime/shared/err-text.mjs +3 -1
- package/src/runtime/shared/error-presentation.mjs +91 -6
- package/src/runtime/shared/handoff-artifacts.d.mts +20 -0
- package/src/runtime/shared/handoff-artifacts.mjs +61 -0
- package/src/runtime/shared/llm/provider-model-identities.mjs +6 -1
- package/src/runtime/shared/llm/usage-accounting.mjs +7 -1
- package/src/runtime/shared/model-route-fallback.mjs +79 -7
- package/src/runtime/shared/plain-preview.mjs +22 -17
- package/src/runtime/shared/sensitive-path-rules.d.mts +15 -0
- package/src/runtime/shared/sensitive-path-rules.mjs +256 -0
- package/src/runtime/shared/usage-readout-totals.mjs +15 -13
- package/src/runtime/shared/user-data-guard.mjs +5 -2
- package/src/session-runtime/agent-home-delivery.mjs +423 -56
- package/src/session-runtime/agent-room-delivery.mjs +45 -4
- package/src/session-runtime/agent-task-sessions.mjs +299 -39
- package/src/session-runtime/boot/apis.mjs +13 -0
- package/src/session-runtime/boot/providers.mjs +14 -4
- package/src/session-runtime/config-lifecycle.mjs +43 -2
- package/src/session-runtime/handoff-attachments.mjs +593 -0
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +27 -3
- package/src/session-runtime/model-route/route-persist.mjs +2 -2
- package/src/session-runtime/model-route/route-tuning.mjs +7 -1
- package/src/session-runtime/model-route/set-route.mjs +21 -1
- package/src/session-runtime/native-web-search.mjs +2 -2
- package/src/session-runtime/new-session-config.mjs +6 -1
- package/src/session-runtime/route-resolution.mjs +5 -11
- package/src/session-runtime/services/agent-tool/helpers.mjs +24 -5
- package/src/session-runtime/services/agent-tool/send-flow.mjs +11 -3
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +4 -1
- package/src/session-runtime/services/agent-tool/spawn-preset.mjs +5 -8
- package/src/session-runtime/services/agent-tool/tool-def.mjs +7 -0
- package/src/session-runtime/setup-tool/executor.mjs +12 -1
- package/src/session-runtime/setup-tool/extended-actions.mjs +19 -7
- package/src/session-runtime/setup-tool/settings-contract.mjs +6 -0
- package/src/session-runtime/tool-policy-refresh.mjs +13 -2
- package/src/session-runtime/turn/turn-run/turn-prepare.mjs +11 -0
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +123 -32
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +67 -7
- package/src/session-runtime/workflow-agents-api/onboarding.mjs +11 -4
- package/src/standalone/daemon-session-control.mjs +13 -5
- package/src/standalone/daemon.mjs +16 -4
- package/src/standalone/session-service/agent-tree/agent-turns.mjs +46 -3
- package/src/standalone/session-service/agent-tree.mjs +4 -3
- package/src/standalone/session-service/session-calls/session-turns.mjs +19 -0
- package/src/tui/dist/index.mjs +70 -9
- package/src/tui/session/notice-surface.mjs +3 -4
- package/src/tui/session/session-api/routes.mjs +14 -3
- package/src/tui/session/transcript-intake.mjs +2 -0
- package/src/tui/session/turn-live-call.mjs +11 -3
- package/src/tui/session/turn.mjs +13 -3
package/NOTICE.md
CHANGED
|
@@ -125,15 +125,58 @@ downloads it from this repository's `effort-judge-v*` GitHub releases, as
|
|
|
125
125
|
listed in `src/runtime/effort-judge/model-manifest.json`.
|
|
126
126
|
|
|
127
127
|
Statement of changes (Apache-2.0 section 4(b)): only the text encoder is kept,
|
|
128
|
-
reduced to
|
|
129
|
-
model is fine-tuned to rate the reasoning effort a request
|
|
130
|
-
are exported to ONNX and quantized to 4 bits. Full license
|
|
131
|
-
`LICENSES/Apache-2.0.txt`.
|
|
132
|
-
|
|
133
|
-
Its training data includes requests from SWE-chat
|
|
134
|
-
(<https://huggingface.co/datasets/
|
|
135
|
-
|
|
136
|
-
|
|
128
|
+
reduced to 18 of its layers; a four-level classification head is added and the
|
|
129
|
+
model is fine-tuned to rate the reasoning effort a request or an agent step
|
|
130
|
+
needs; the weights are exported to ONNX and quantized to 4 bits. Full license
|
|
131
|
+
text: `LICENSES/Apache-2.0.txt`.
|
|
132
|
+
|
|
133
|
+
Its training data includes requests and agent steps from SWE-chat
|
|
134
|
+
(<https://huggingface.co/datasets/SALT-NLP/SWE-chat>, Open Data Commons
|
|
135
|
+
Attribution License 1.0); OpenAssistant oasst2
|
|
136
|
+
(<https://huggingface.co/datasets/OpenAssistant/oasst2>, Apache License 2.0);
|
|
137
|
+
DataClaw exports that their authors published on the Hugging Face Hub under the
|
|
138
|
+
MIT License (<https://huggingface.co/datasets/di-zhang-fdu/ShareDataClaw>);
|
|
139
|
+
DevGPT by Tao Xiao, Christoph Treude, Hideaki Hata and Kenichi Matsumoto
|
|
140
|
+
(<https://doi.org/10.5281/zenodo.16392320>, CC BY 4.0); issue texts from the
|
|
141
|
+
SWE-bench training split (<https://github.com/SWE-bench/SWE-bench>, MIT
|
|
142
|
+
License); and agent steps from NVIDIA's SWE-Hero OpenHands trajectories
|
|
143
|
+
(<https://huggingface.co/datasets/nvidia/SWE-Hero-openhands-trajectories>,
|
|
144
|
+
CC BY 4.0).
|
|
145
|
+
|
|
146
|
+
Contains information from WildChat-4.8M
|
|
147
|
+
(<https://huggingface.co/datasets/allenai/WildChat-4.8M>) which is made
|
|
148
|
+
available under the ODC Attribution License
|
|
149
|
+
(<https://opendatacommons.org/licenses/by/1-0/>).
|
|
150
|
+
|
|
151
|
+
Since `effort-judge-v7` it also includes questions from Stack Exchange sites
|
|
152
|
+
(via <https://huggingface.co/datasets/HuggingFaceTB/stackexchange_2025_md>;
|
|
153
|
+
each post is licensed CC BY-SA 2.5, 3.0 or 4.0 by its author, and its URL and
|
|
154
|
+
author are kept with the training item); GitHub issues and pull requests of
|
|
155
|
+
permissively licensed repositories (via
|
|
156
|
+
<https://huggingface.co/datasets/common-pile/github_archive>, with each item's
|
|
157
|
+
repository, URL, license and authors kept); issues and pull requests from
|
|
158
|
+
Nebius SWE-rebench-V2 (<https://huggingface.co/datasets/nebius/SWE-rebench-V2>,
|
|
159
|
+
<https://huggingface.co/datasets/nebius/SWE-rebench-V2-PRs>, CC BY 4.0,
|
|
160
|
+
permissively licensed repositories only); and agent steps from Nebius
|
|
161
|
+
SWE-agent trajectories
|
|
162
|
+
(<https://huggingface.co/datasets/nebius/SWE-agent-trajectories>, CC BY 4.0),
|
|
163
|
+
Nebius SWE-rebench OpenHands trajectories
|
|
164
|
+
(<https://huggingface.co/datasets/nebius/SWE-rebench-openhands-trajectories>,
|
|
165
|
+
CC BY 4.0), Kwai-Klear SWE-smith mini-swe-agent-plus trajectories
|
|
166
|
+
(<https://huggingface.co/datasets/Kwai-Klear/SWE-smith-mini_swe_agent_plus-trajectories-66k>,
|
|
167
|
+
MIT License), SWE-Factory DeepSWE-Agent Kimi-K2 trajectories
|
|
168
|
+
(<https://huggingface.co/datasets/SWE-Factory/DeepSWE-Agent-Kimi-K2-Trajectories-2.8K>,
|
|
169
|
+
MIT License), SWE-Gym OpenHands SFT trajectories
|
|
170
|
+
(<https://huggingface.co/datasets/SWE-Gym/OpenHands-SFT-Trajectories>, MIT
|
|
171
|
+
License), SWE-ZERO-12M trajectories
|
|
172
|
+
(<https://huggingface.co/datasets/AlienKevin/SWE-ZERO-12M-trajectories>, Apache
|
|
173
|
+
License 2.0), SWE-Lego real and synthetic data
|
|
174
|
+
(<https://huggingface.co/datasets/Lego-X/SWE-Lego-Real-Data>,
|
|
175
|
+
<https://huggingface.co/datasets/Lego-X/SWE-Lego-Synthetic-Data>, Apache
|
|
176
|
+
License 2.0) and TIGER-Lab SWE-Next SFT trajectories
|
|
177
|
+
(<https://huggingface.co/datasets/TIGER-Lab/SWE-Next-SFT-Trajectories>, MIT
|
|
178
|
+
License). Each `effort-judge-v*` release lists its files, hashes and
|
|
179
|
+
attributions.
|
|
137
180
|
|
|
138
181
|
## CC0-1.0
|
|
139
182
|
|
package/package.json
CHANGED
|
@@ -116,6 +116,7 @@
|
|
|
116
116
|
"8d343d0a406fd5817b7fd98a3ac47010",
|
|
117
117
|
"a1b73ce404125d3ce0a5762e4a1e1555",
|
|
118
118
|
"a28fb01bb21ceebbde1bc6c4a02d3db6",
|
|
119
|
+
"c7fdabb946eed7283db656493d95749b",
|
|
119
120
|
"d40c23517c4803afdac3fc056bb65cda",
|
|
120
121
|
"db1af5417849abc2f6bb1d1d2b63939f"
|
|
121
122
|
],
|
|
@@ -344,6 +345,7 @@
|
|
|
344
345
|
"0d6926aaca2890da9347f15a826546e3",
|
|
345
346
|
"0f14ba0a3d8b3896b717dc144bbe49a4",
|
|
346
347
|
"15d86146cfbd58d85adf0c25cf1d683f",
|
|
348
|
+
"18dc665b96ee0ba5a1645180e173b1af",
|
|
347
349
|
"1c317db86e1ff80a5c4102e09e36f5fb",
|
|
348
350
|
"242f11864abdef90fa0cc9cb4599a579",
|
|
349
351
|
"29a347c4d3a2f773fa92c627260301ba",
|
|
@@ -374,7 +376,8 @@
|
|
|
374
376
|
"ff18ac1a9f5961925aec27ffb870bae0"
|
|
375
377
|
],
|
|
376
378
|
"setup-guide": [
|
|
377
|
-
"633e15b84dbe22f2b578b67cc35853d4"
|
|
379
|
+
"633e15b84dbe22f2b578b67cc35853d4",
|
|
380
|
+
"920d5b29ccfe6c88f623cf0892b29285"
|
|
378
381
|
],
|
|
379
382
|
"skill-creator": [
|
|
380
383
|
"020817866da73a69544ba35086bdcd5f",
|
|
@@ -52,7 +52,7 @@ Read this when choosing a `setup` mutation.
|
|
|
52
52
|
| Remove stored provider authentication (one OAuth account at a time) | `forget_provider_auth` |
|
|
53
53
|
| Select, rename, or reorder OAuth accounts, set the switching policy, or allow paid credits | `set_provider_account` |
|
|
54
54
|
| Developer options such as risk-gated OAuth providers | `set_developer_option` |
|
|
55
|
-
| Connect a catalog service (
|
|
55
|
+
| Connect a catalog service (Notion, Linear, Gmail, …; not GitHub, which is the GitHub CLI) for the user: shows a one-click connect card | `connect_connector` |
|
|
56
56
|
| Add an MCP server | `add_mcp_server` |
|
|
57
57
|
| Edit or rename an MCP server | `save_mcp_server` |
|
|
58
58
|
| Remove an MCP server | `remove_mcp_server` |
|
|
@@ -112,6 +112,9 @@ workflow` before changing the corresponding domain.
|
|
|
112
112
|
`originalName` and `name`. Skill deletion is not exposed; disable it instead.
|
|
113
113
|
Built-in and plugin skills accept only `toolDependencies` edits (`null`
|
|
114
114
|
restores their declared dependencies).
|
|
115
|
+
- A created agent is a bot (`definition.kind: "bot"`) or a workflow agent
|
|
116
|
+
(`"agent"`); omitted, the representative bot's chat creates a bot and any other chat a
|
|
117
|
+
workflow agent. The kind is fixed after creation.
|
|
115
118
|
- Changing orchestration does not rewrite workflow instructions or agents.
|
|
116
119
|
|
|
117
120
|
## Providers and authentication
|
|
@@ -16,7 +16,7 @@ through file edits. One named setting the user already chose belongs to `setup`.
|
|
|
16
16
|
|
|
17
17
|
## Style
|
|
18
18
|
|
|
19
|
-
Reply as in
|
|
19
|
+
Reply as in bot mode: one step or one concept per message, short plain
|
|
20
20
|
sentences, no tables or headings, in the user's language. In Korean use the
|
|
21
21
|
formal polite style (~합니다 / ~하세요, never ~해요). Say "봇" for Mixy and
|
|
22
22
|
other contacts, "에이전트" only for workflow agents. Never print ids, file
|
|
@@ -67,8 +67,8 @@ connector links an outside service so bots and agents can read and act in it,
|
|
|
67
67
|
and anything that sends or posts asks first through an approval card. Then
|
|
68
68
|
suggest by what the user does, only these: Gmail (with a Google app password;
|
|
69
69
|
it needs 2-Step Verification on the Google account, and the connect window
|
|
70
|
-
opens the app-password page in the browser),
|
|
71
|
-
|
|
70
|
+
opens the app-password page in the browser), Notion, Linear or Jira. GitHub is
|
|
71
|
+
not a connector; it is the signed-in GitHub CLI of Git & GitHub. Do not suggest Google Calendar or Google
|
|
72
72
|
Drive; their Google sign-in is still under review. Connect one with
|
|
73
73
|
`connect_connector`; it only leaves a card, so tell the user to press it and
|
|
74
74
|
confirm with `status mcp`.
|
|
@@ -142,7 +142,7 @@ step; do not insist.
|
|
|
142
142
|
|
|
143
143
|
## Glossary
|
|
144
144
|
|
|
145
|
-
- Bot (봇):
|
|
145
|
+
- Bot (봇): a contact you chat with in bot mode (봇 모드). Mixy is the representative
|
|
146
146
|
bot; the user can have it make others, such as a GitHub Watcher.
|
|
147
147
|
- Agent (에이전트): a workflow sub-agent such as Worker or Reviewer that
|
|
148
148
|
does part of a task. Users add their own on the Workflows page with the
|
|
@@ -150,12 +150,15 @@ step; do not insist.
|
|
|
150
150
|
- Default agents (기본 에이전트): built-in helpers listed on Workflows, such as
|
|
151
151
|
Web Search (runs the web search tool) and the Maintainer (memory upkeep and
|
|
152
152
|
session titles). They need a model route to work.
|
|
153
|
-
-
|
|
153
|
+
- Agent mode (에이전트 모드): a coding work session run by Lead and agents.
|
|
154
|
+
A session a bot starts for a job is an agent task session (에이전트 작업
|
|
155
|
+
세션); others are just sessions (세션).
|
|
156
|
+
- Sessions and projects: an agent-mode session runs in a Project, a folder whose
|
|
154
157
|
instructions and memories it loads.
|
|
155
158
|
- Workflows and work rules: a workflow sets how a request gets done; work
|
|
156
159
|
rules are the instructions it applies.
|
|
157
|
-
- Connectors and extensions: connectors are MCP services such as
|
|
158
|
-
|
|
160
|
+
- Connectors and extensions: connectors are MCP services such as Notion or
|
|
161
|
+
Linear (`connect_connector`, the user presses the card); extensions are
|
|
159
162
|
plugins that add tools and skills that teach how to work.
|
|
160
163
|
- Group rooms (그룹 대화방): one chat with several bots. `@name` or "봇 부르기"
|
|
161
164
|
addresses one bot; otherwise the Maintainer decides who answers next.
|
|
@@ -20,15 +20,20 @@ partial: true
|
|
|
20
20
|
destructive-action confirmations; quote needed error text exactly.
|
|
21
21
|
|
|
22
22
|
Layout (GitHub-flavored Markdown, `$$…$$` for display math): the content picks
|
|
23
|
-
the format at every depth; depth sets only how much is said.
|
|
23
|
+
the format at every depth; depth sets only how much is said. There is no fixed
|
|
24
|
+
template: a reply's shape follows what it says, so consecutive replies look
|
|
25
|
+
different when their content differs.
|
|
24
26
|
|
|
25
|
-
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
- An explanation, a single answer, or a cause and its effect is short prose.
|
|
28
|
+
- Items that share two or more attributes (status of several tasks, options
|
|
29
|
+
and their costs, before/after, provider × behavior) are a small table with
|
|
30
|
+
short cells, not a list of labelled bullets.
|
|
31
|
+
- Ordered steps are a numbered list; three or more parallel, independent
|
|
32
|
+
points are a flat list; never nested.
|
|
33
|
+
- Mixed content opens with one sentence carrying the outcome, then uses
|
|
34
|
+
whichever of the forms above fits each part. Plain labels only separate
|
|
35
|
+
parts that are long and genuinely different; never label every short part.
|
|
36
|
+
- What the reader must decide or do comes last, on its own.
|
|
32
37
|
- Commands, paths, identifiers, and literals go in code; multi-line code,
|
|
33
38
|
diffs, and output in fenced blocks.
|
|
34
39
|
- Bold only what the reader scans for: the decision or warning they must not
|
|
@@ -12,10 +12,17 @@
|
|
|
12
12
|
requested scope and existing permissions. You alone create, edit or remove
|
|
13
13
|
bots, and you manage every bot's routines and settings; other bots manage
|
|
14
14
|
only their own.
|
|
15
|
-
- Users call
|
|
15
|
+
- Users call bot-mode contacts (you and the ones made for them) "bots"
|
|
16
16
|
(봇), and the workflow sub-agents (Worker, Reviewer, …) "agents"
|
|
17
|
-
(에이전트)
|
|
17
|
+
(에이전트). Chatting with a bot is "bot mode" (봇 모드); a coding work
|
|
18
|
+
session run by Lead and agents is "agent mode" (에이전트 모드). A session
|
|
19
|
+
you start with `session create` is an "agent task session" (에이전트 작업
|
|
20
|
+
세션); any other is a "session" (세션). Use those words with the user.
|
|
18
21
|
- You coordinate the user's bots and agents: route a request to the one best
|
|
19
|
-
suited for it (a bot, a sub-agent, or a new
|
|
22
|
+
suited for it (a bot, a sub-agent, or a new agent task session for
|
|
20
23
|
substantial coding) with a self-contained brief, start it when already
|
|
21
|
-
requested, otherwise suggest it, and follow up with the result.
|
|
24
|
+
requested, otherwise suggest it, and follow up with the result. Promise a
|
|
25
|
+
follow-up only for work that reports back: a bot, a sub-agent or an agent
|
|
26
|
+
task session you created, or a `session send` whose result says
|
|
27
|
+
reportsBack: true. Otherwise say it was sent and that the user can check
|
|
28
|
+
that session.
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
import { createHash } from 'node:crypto';
|
|
4
4
|
import { existsSync, readdirSync } from 'node:fs';
|
|
5
|
-
import { join } from 'node:path';
|
|
5
|
+
import { basename, dirname, join } from 'node:path';
|
|
6
6
|
import { compareCodePoints } from '../../../shared/code-point-order.mjs';
|
|
7
|
+
import { BOTS_DIR, MIXY_BOT_ID, botStoreActive, isStoreBot, mixyIdentityDir } from '../../../shared/agent-store.mjs';
|
|
7
8
|
import { mixdogRoot } from '../../../shared/plugin-paths.mjs';
|
|
8
9
|
import { readMarkdownDocument } from '../../../shared/markdown-frontmatter.mjs';
|
|
9
10
|
import { listHiddenAgentsByKind, getAgentCatalogShareAgents } from '../internal-agents.mjs';
|
|
@@ -89,9 +90,35 @@ function agentSectionDirs(pluginRoot) {
|
|
|
89
90
|
} catch {
|
|
90
91
|
/* unresolvable data dir — built-in roles still load */
|
|
91
92
|
}
|
|
93
|
+
// Bots of the store (agent-store.mjs), last: a bot's own folder wins over
|
|
94
|
+
// the agents/ original the split left behind.
|
|
95
|
+
const root = userDataRoot();
|
|
96
|
+
if (root && botStoreActive(root)) dirs.push(join(root, BOTS_DIR));
|
|
92
97
|
return dirs;
|
|
93
98
|
}
|
|
94
99
|
|
|
100
|
+
// The user data dir (parent of agents/), or '' when it cannot be resolved.
|
|
101
|
+
function userDataRoot() {
|
|
102
|
+
try {
|
|
103
|
+
const userDir = mixdogGlobalDir('agents');
|
|
104
|
+
return userDir ? dirname(userDir) : '';
|
|
105
|
+
} catch {
|
|
106
|
+
return '';
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// A store bot's own folder, or ''.
|
|
111
|
+
function storeBotDir(agent) {
|
|
112
|
+
const root = userDataRoot();
|
|
113
|
+
return root && isStoreBot(root, agent) ? join(root, BOTS_DIR, agent) : '';
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Mixy's identity folder: bots/mixy with the store, agents/lead before.
|
|
117
|
+
function mixyDir() {
|
|
118
|
+
const root = userDataRoot();
|
|
119
|
+
return root ? mixyIdentityDir(root) : '';
|
|
120
|
+
}
|
|
121
|
+
|
|
95
122
|
function loadAgentSections(pluginRoot) {
|
|
96
123
|
// agents/ accepts both the compatibility flat layout and the current
|
|
97
124
|
// nested agents/<agent>/AGENT.md layout.
|
|
@@ -117,6 +144,7 @@ function loadAgentSections(pluginRoot) {
|
|
|
117
144
|
// Mixy's own AGENT.md (agents/lead/) rides only Mixy's agent-mode
|
|
118
145
|
// prompt (loadMixyRoleSection), never another role catalog.
|
|
119
146
|
if (!name || !raw || name === 'lead') continue;
|
|
147
|
+
if (name === MIXY_BOT_ID && basename(agentsDir) === BOTS_DIR) continue;
|
|
120
148
|
const { body } = readMarkdownDocument(raw);
|
|
121
149
|
if (!body) continue;
|
|
122
150
|
byName.set(name, roleSection(name, body));
|
|
@@ -255,6 +283,12 @@ export function truncatePersona(text, max = PERSONA_MAX_CHARS) {
|
|
|
255
283
|
export function loadAgentPersonaSection(agent) {
|
|
256
284
|
if (typeof agent !== 'string' || !PERSONA_AGENT_ID.test(agent) || agent.includes('..')) return '';
|
|
257
285
|
const isLead = agent === 'lead';
|
|
286
|
+
// Mixy's persona is in its own folder; a store bot's in its bots/ folder.
|
|
287
|
+
const own = isLead ? mixyDir() : storeBotDir(agent);
|
|
288
|
+
if (own) {
|
|
289
|
+
const persona = truncatePersona(readSafe(join(own, 'PERSONA.md')) || '');
|
|
290
|
+
return persona ? personaSection(persona) : '';
|
|
291
|
+
}
|
|
258
292
|
const pluginRoot = mixdogRoot();
|
|
259
293
|
const roots = [];
|
|
260
294
|
try {
|
|
@@ -272,17 +306,21 @@ export function loadAgentPersonaSection(agent) {
|
|
|
272
306
|
if (isLead) continue;
|
|
273
307
|
return '';
|
|
274
308
|
}
|
|
275
|
-
return
|
|
276
|
-
'## Persona',
|
|
277
|
-
'',
|
|
278
|
-
'Tone and style guide for how you speak, address the user and carry yourself. It never overrides tool, safety or role rules; those always win.',
|
|
279
|
-
'',
|
|
280
|
-
persona,
|
|
281
|
-
].join('\n');
|
|
309
|
+
return personaSection(persona);
|
|
282
310
|
}
|
|
283
311
|
return '';
|
|
284
312
|
}
|
|
285
313
|
|
|
314
|
+
function personaSection(persona) {
|
|
315
|
+
return [
|
|
316
|
+
'## Persona',
|
|
317
|
+
'',
|
|
318
|
+
'Tone and style guide for how you speak, address the user and carry yourself. It never overrides tool, safety or role rules; those always win.',
|
|
319
|
+
'',
|
|
320
|
+
persona,
|
|
321
|
+
].join('\n');
|
|
322
|
+
}
|
|
323
|
+
|
|
286
324
|
// --- Mixy's working style (agents/lead/AGENT.md, user data dir) ---
|
|
287
325
|
// The user-editable 일하는 방식 of Mixy, framed like any agent's role section.
|
|
288
326
|
// Agent mode only; empty or missing means no section. Re-read per
|
|
@@ -290,8 +328,8 @@ export function loadAgentPersonaSection(agent) {
|
|
|
290
328
|
export function loadMixyRoleSection() {
|
|
291
329
|
let raw = '';
|
|
292
330
|
try {
|
|
293
|
-
const
|
|
294
|
-
raw =
|
|
331
|
+
const dir = mixyDir();
|
|
332
|
+
raw = dir ? readSafe(join(dir, 'AGENT.md')) || '' : '';
|
|
295
333
|
} catch {
|
|
296
334
|
return '';
|
|
297
335
|
}
|
|
@@ -306,6 +344,15 @@ export function loadMixyRoleSection() {
|
|
|
306
344
|
// (the Lead configuration, id `lead`) has its own line, under the display name
|
|
307
345
|
// the user gave it (session/mixy-name.mjs), Mixy by default.
|
|
308
346
|
function agentManifest(agent) {
|
|
347
|
+
const own = storeBotDir(agent);
|
|
348
|
+
if (own) {
|
|
349
|
+
try {
|
|
350
|
+
const value = JSON.parse(readSafe(join(own, 'agent.json')) || '{}');
|
|
351
|
+
return value && typeof value === 'object' ? value : {};
|
|
352
|
+
} catch {
|
|
353
|
+
return {};
|
|
354
|
+
}
|
|
355
|
+
}
|
|
309
356
|
const roots = [];
|
|
310
357
|
try {
|
|
311
358
|
const userDir = mixdogGlobalDir('agents');
|
|
@@ -344,9 +391,13 @@ export function agentModeIdentityLine(agent) {
|
|
|
344
391
|
// the shipped tree — as one hash. A session stamps it when its prompt is
|
|
345
392
|
// composed; another value means the profile was edited since
|
|
346
393
|
// (session-runtime/tool-policy-refresh.mjs refreshAgentProfile). '' for an
|
|
347
|
-
// invalid id.
|
|
348
|
-
|
|
394
|
+
// invalid id. A coding Lead (`lead` outside Mixy's own thread) embeds no
|
|
395
|
+
// profile file at all, so its stamp is a constant: editing Mixy never
|
|
396
|
+
// rebuilds a coding session's prompt.
|
|
397
|
+
export const CODING_LEAD_PROFILE_REVISION = 'coding-lead';
|
|
398
|
+
export function agentProfileRevision(agent, { mixy = true } = {}) {
|
|
349
399
|
if (typeof agent !== 'string' || !PERSONA_AGENT_ID.test(agent) || agent.includes('..')) return '';
|
|
400
|
+
if (agent === 'lead' && !mixy) return CODING_LEAD_PROFILE_REVISION;
|
|
350
401
|
const roots = [mixdogGlobalDir('agents')];
|
|
351
402
|
const pluginRoot = mixdogRoot();
|
|
352
403
|
if (pluginRoot) roots.push(join(pluginRoot, 'agents'));
|
|
@@ -356,6 +407,13 @@ export function agentProfileRevision(agent) {
|
|
|
356
407
|
hash.update(`${root}\0${file}\0${readSafe(join(root, agent, file)) ?? '\u0001'}\0`);
|
|
357
408
|
}
|
|
358
409
|
}
|
|
410
|
+
// Mixy's or a store bot's own folder, when it has one.
|
|
411
|
+
const own = agent === 'lead' ? mixyDir() : storeBotDir(agent);
|
|
412
|
+
if (own && own !== join(roots[0] || '', agent)) {
|
|
413
|
+
for (const file of ['agent.json', 'AGENT.md', 'PERSONA.md']) {
|
|
414
|
+
hash.update(`${own}\0${file}\0${readSafe(join(own, file)) ?? '\u0001'}\0`);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
359
417
|
return hash.digest('hex').slice(0, 24);
|
|
360
418
|
}
|
|
361
419
|
|
|
@@ -417,8 +475,8 @@ export function composeSystemPrompt(opts) {
|
|
|
417
475
|
? loadMixyRoleSection()
|
|
418
476
|
: loadScopedRoleInstructions(opts.agent || null, opts.provider || null);
|
|
419
477
|
}
|
|
420
|
-
// Persona follows the role;
|
|
421
|
-
//
|
|
478
|
+
// Persona follows the role; Mixy's own thread carries Mixy's persona
|
|
479
|
+
// (bots/mixy/PERSONA.md) — a coding Lead's prompt never does (skipPersona).
|
|
422
480
|
const personaContext = opts.agent && !opts.skipPersona ? loadAgentPersonaSection(opts.agent) : '';
|
|
423
481
|
const coreMemory = skip.memory ? '' : trimmedPromptSlice(opts.coreMemoryContext);
|
|
424
482
|
// User AGENTS.md / CLAUDE.md block (context/instruction-files.mjs), already
|
|
@@ -14,6 +14,7 @@ import { readFileSync, statSync } from 'node:fs';
|
|
|
14
14
|
import { join } from 'node:path';
|
|
15
15
|
import { cwdWithinProjects } from '../../../shared/extension-scopes.mjs';
|
|
16
16
|
import { resolvePluginData } from '../../../shared/plugin-paths.mjs';
|
|
17
|
+
import { userDefinitionDir } from '../../../shared/agent-store.mjs';
|
|
17
18
|
import { isSelfMcpToolName, parseMcpToolName } from '../../../shared/tool-primitives.mjs';
|
|
18
19
|
import { connectorToolDefault } from '../../../shared/connector-catalog.mjs';
|
|
19
20
|
import { serverConnector } from './server-connectors.mjs';
|
|
@@ -149,7 +150,7 @@ export function readConnectorsFile(path) {
|
|
|
149
150
|
export function agentConnectors(agentId, dataDir = resolvePluginData()) {
|
|
150
151
|
const id = clean(agentId);
|
|
151
152
|
if (!id || !AGENT_DIR_ID.test(id)) return null;
|
|
152
|
-
return cachedRead(join(dataDir,
|
|
153
|
+
return cachedRead(join(userDefinitionDir(dataDir, id), 'agent.json'), readConnectorsFile);
|
|
153
154
|
}
|
|
154
155
|
|
|
155
156
|
/** Uncached: the project policy file → `[{ root, off }]`, null without one,
|
|
@@ -187,9 +187,14 @@ export function normalizeAntigravityCatalog(rawModels) {
|
|
|
187
187
|
return models.sort((a, b) => a.display.localeCompare(b.display));
|
|
188
188
|
}
|
|
189
189
|
|
|
190
|
-
/**
|
|
190
|
+
/**
|
|
191
|
+
* Catalog to resolve wire ids against: in-memory mirror, disk cache, then the
|
|
192
|
+
* curated fallback. Sends never refresh the catalog, so the account's last live
|
|
193
|
+
* list is used even past its TTL: it names the wire ids this account was
|
|
194
|
+
* offered, which the curated list can only approximate.
|
|
195
|
+
*/
|
|
191
196
|
function antigravityCatalogModels() {
|
|
192
|
-
if (!_mirror) _mirror = antigravityModelCache.loadSync();
|
|
197
|
+
if (!_mirror) _mirror = antigravityModelCache.loadSync({ allowStale: true });
|
|
193
198
|
return _mirror || ANTIGRAVITY_MODELS;
|
|
194
199
|
}
|
|
195
200
|
|
|
@@ -31,14 +31,14 @@ export const AUTO_EFFORT_LEVELS = Object.freeze(['easy', 'normal', 'hard', 'very
|
|
|
31
31
|
const STEP_OF_LEVEL = [-1, 0, 1, 2];
|
|
32
32
|
|
|
33
33
|
// The chosen level minimises the expected cost under the judge distribution.
|
|
34
|
-
// A miss costs one per level, plus extra for an opposite call
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
//
|
|
38
|
-
//
|
|
34
|
+
// A miss costs one per level, plus extra for an opposite call. Opposite calls
|
|
35
|
+
// are asymmetric: "easy" for a hard turn degrades the answer, "hard" for an
|
|
36
|
+
// easy turn only costs tokens. On the held-out test splits the heavier
|
|
37
|
+
// under-call cost cut hard-as-easy calls by a third (20 -> 13 of 7,180) for
|
|
38
|
+
// -0.2 points of exact accuracy. "Very hard" carries no extra cost: an extra
|
|
39
|
+
// penalty there let judge v7 pick xhigh on only 17% of very hard turns.
|
|
39
40
|
export const AUTO_EFFORT_UNDER_OPPOSITE_COST = 3;
|
|
40
41
|
export const AUTO_EFFORT_OVER_OPPOSITE_COST = 1;
|
|
41
|
-
export const AUTO_EFFORT_FALSE_VERY_HARD_COST = 1;
|
|
42
42
|
// Ties keep the default first, then the cheaper side.
|
|
43
43
|
const TIE_ORDER = [1, 0, 2, 3];
|
|
44
44
|
|
|
@@ -49,8 +49,7 @@ function expectedCost(values, level) {
|
|
|
49
49
|
p *
|
|
50
50
|
(Math.abs(level - actual) +
|
|
51
51
|
(level === 0 && actual >= 2 ? AUTO_EFFORT_UNDER_OPPOSITE_COST : 0) +
|
|
52
|
-
(actual === 0 && level >= 2 ? AUTO_EFFORT_OVER_OPPOSITE_COST : 0)
|
|
53
|
-
(level === 3 && actual < 3 ? AUTO_EFFORT_FALSE_VERY_HARD_COST : 0));
|
|
52
|
+
(actual === 0 && level >= 2 ? AUTO_EFFORT_OVER_OPPOSITE_COST : 0));
|
|
54
53
|
});
|
|
55
54
|
return cost;
|
|
56
55
|
}
|
|
@@ -10,6 +10,7 @@ import { mergeFlatSchemaProperty } from './flat-schema-merge.mjs';
|
|
|
10
10
|
import { reportedCostUsd } from './usage-primitives.mjs';
|
|
11
11
|
import { reportInvalidTool, wireInputSchema } from './claude-bridge-schema.mjs';
|
|
12
12
|
import { normalizeServerToolUse } from './anthropic-server-tool-usage.mjs';
|
|
13
|
+
import { ANTHROPIC_TOOL_CALL_IDS, withWireToolCallIds } from './tool-call-wire-ids.mjs';
|
|
13
14
|
export const ANTHROPIC_CACHE_TTL_STABLE = { type: 'ephemeral', ttl: '1h' };
|
|
14
15
|
const ANTHROPIC_CACHE_TTL_VOLATILE = { type: 'ephemeral' };
|
|
15
16
|
|
|
@@ -232,7 +233,8 @@ const ANTHROPIC_NATIVE_PROVIDERS = new Set(['anthropic', 'anthropic-oauth']);
|
|
|
232
233
|
|
|
233
234
|
// `provider`: the engine's provider name. A gateway on a native Messages
|
|
234
235
|
// route (wire-route.mjs) also replays the references it tagged itself.
|
|
235
|
-
export function toAnthropicMessages(
|
|
236
|
+
export function toAnthropicMessages(transcript, availableTools, provider = '') {
|
|
237
|
+
const messages = withWireToolCallIds(transcript, ANTHROPIC_TOOL_CALL_IDS);
|
|
236
238
|
const ownProvider = String(provider || '').toLowerCase();
|
|
237
239
|
const availableNames = anthropicToolNameSet(availableTools);
|
|
238
240
|
const result = [];
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// Tool-call ids at the wire. A transcript keeps each tool call's id as the
|
|
2
|
+
// provider that produced it minted it; after a model switch another provider
|
|
3
|
+
// may refuse it (Anthropic accepts only [A-Za-z0-9_-]; OpenAI chat caps the
|
|
4
|
+
// length). Each request builder projects the ids onto its own rule just
|
|
5
|
+
// before lowering: a valid id passes unchanged (so native replay items and
|
|
6
|
+
// the provider's own ids stay byte-exact), an invalid one becomes a
|
|
7
|
+
// deterministic, collision-free stand-in, and a call and its result always
|
|
8
|
+
// map to the same value. Persisted history is never rewritten.
|
|
9
|
+
import { createHash } from 'node:crypto';
|
|
10
|
+
|
|
11
|
+
export const ANTHROPIC_TOOL_CALL_IDS = Object.freeze({ allowed: /^[A-Za-z0-9_-]+$/, maxLength: 64 });
|
|
12
|
+
export const OPENAI_RESPONSES_TOOL_CALL_IDS = Object.freeze({ allowed: /^[A-Za-z0-9_.:-]+$/, maxLength: 64 });
|
|
13
|
+
export const OPENAI_CHAT_TOOL_CALL_IDS = Object.freeze({ allowed: /^[A-Za-z0-9_.:-]+$/, maxLength: 40 });
|
|
14
|
+
|
|
15
|
+
const HASH_CHARS = 10;
|
|
16
|
+
|
|
17
|
+
function standIn(id, rule, salt) {
|
|
18
|
+
const hash = createHash('sha256').update(`${salt}\u0000${id}`).digest('hex').slice(0, HASH_CHARS);
|
|
19
|
+
const stem = String(id)
|
|
20
|
+
.replace(/[^A-Za-z0-9_-]+/g, '_')
|
|
21
|
+
.replace(/^_+|_+$/g, '')
|
|
22
|
+
.slice(0, Math.max(0, rule.maxLength - HASH_CHARS - 1));
|
|
23
|
+
return stem ? `${stem}_${hash}` : `call_${hash}`.slice(0, rule.maxLength);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const isValid = (id, rule) => id.length > 0 && id.length <= rule.maxLength && rule.allowed.test(id);
|
|
27
|
+
|
|
28
|
+
/** id → wire id for every tool call and result in `messages` under `rule`. */
|
|
29
|
+
export function toolCallWireIdMap(messages, rule) {
|
|
30
|
+
const ids = new Set();
|
|
31
|
+
for (const message of Array.isArray(messages) ? messages : []) {
|
|
32
|
+
if (message?.role === 'assistant')
|
|
33
|
+
for (const call of message.toolCalls || []) if (call?.id) ids.add(String(call.id));
|
|
34
|
+
if (message?.role === 'tool' && message.toolCallId) ids.add(String(message.toolCallId));
|
|
35
|
+
}
|
|
36
|
+
const map = new Map();
|
|
37
|
+
const taken = new Set([...ids].filter((id) => isValid(id, rule)));
|
|
38
|
+
for (const id of ids) {
|
|
39
|
+
if (isValid(id, rule)) continue;
|
|
40
|
+
let salt = 0;
|
|
41
|
+
let wire = standIn(id, rule, salt);
|
|
42
|
+
while (taken.has(wire)) wire = standIn(id, rule, ++salt);
|
|
43
|
+
taken.add(wire);
|
|
44
|
+
map.set(id, wire);
|
|
45
|
+
}
|
|
46
|
+
return map;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** `messages` with tool-call ids projected onto `rule`; the same array when none needs it. */
|
|
50
|
+
export function withWireToolCallIds(messages, rule) {
|
|
51
|
+
const map = toolCallWireIdMap(messages, rule);
|
|
52
|
+
if (!map.size) return messages;
|
|
53
|
+
return messages.map((message) => {
|
|
54
|
+
if (message?.role === 'tool' && map.has(String(message.toolCallId))) {
|
|
55
|
+
return { ...message, toolCallId: map.get(String(message.toolCallId)) };
|
|
56
|
+
}
|
|
57
|
+
if (message?.role !== 'assistant' || !message.toolCalls?.some((call) => map.has(String(call?.id)))) return message;
|
|
58
|
+
return {
|
|
59
|
+
...message,
|
|
60
|
+
toolCalls: message.toolCalls.map((call) =>
|
|
61
|
+
map.has(String(call?.id)) ? { ...call, id: map.get(String(call.id)) } : call
|
|
62
|
+
),
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
}
|
|
@@ -104,10 +104,16 @@ export const COMPAT_RETRY_PROFILES = Object.freeze({
|
|
|
104
104
|
}),
|
|
105
105
|
});
|
|
106
106
|
|
|
107
|
-
|
|
107
|
+
// A provider without a profile (custom endpoints, gateways, local servers)
|
|
108
|
+
// keeps the shared ladder, but a Retry-After beyond a minute is not waited
|
|
109
|
+
// out: it surfaces with its wait so the account pool can rotate and the
|
|
110
|
+
// notice can name when to try again.
|
|
111
|
+
export const COMPAT_DEFAULT_MAX_RETRY_AFTER_MS = 60_000;
|
|
112
|
+
|
|
113
|
+
/** withRetry options (attempt budget, schedule, jitter) for a provider; only the advice ceiling for the shared defaults. */
|
|
108
114
|
export function compatRetryOptions(providerName) {
|
|
109
115
|
const profile = COMPAT_RETRY_PROFILES[providerName];
|
|
110
|
-
if (!profile) return {};
|
|
116
|
+
if (!profile) return { maxRetryAfterMs: COMPAT_DEFAULT_MAX_RETRY_AFTER_MS };
|
|
111
117
|
return {
|
|
112
118
|
maxAttempts: profile.maxAttempts,
|
|
113
119
|
backoffMs: profile.backoffMs,
|
|
@@ -17,6 +17,11 @@ import {
|
|
|
17
17
|
} from './media-normalization.mjs';
|
|
18
18
|
import { customToolCallFromResponseItem, nativeToolSearchCallFromArguments } from './custom-tool-wire.mjs';
|
|
19
19
|
import { providerReplayItems } from './lib/provider-replay.mjs';
|
|
20
|
+
import {
|
|
21
|
+
OPENAI_CHAT_TOOL_CALL_IDS,
|
|
22
|
+
OPENAI_RESPONSES_TOOL_CALL_IDS,
|
|
23
|
+
withWireToolCallIds,
|
|
24
|
+
} from './lib/tool-call-wire-ids.mjs';
|
|
20
25
|
import { acceptedWireTools } from './lib/claude-bridge-schema.mjs';
|
|
21
26
|
import { ensureResponsesCallOutputs } from './lib/wire-pairing.mjs';
|
|
22
27
|
import { responsesEffortUpdates } from './effort-configuration.mjs';
|
|
@@ -34,7 +39,8 @@ export function resolveCompatMaxOutputTokens(opts = {}) {
|
|
|
34
39
|
);
|
|
35
40
|
}
|
|
36
41
|
|
|
37
|
-
export function toOpenAIMessages(
|
|
42
|
+
export function toOpenAIMessages(transcript, providerName, options = {}) {
|
|
43
|
+
const messages = withWireToolCallIds(transcript, OPENAI_CHAT_TOOL_CALL_IDS);
|
|
38
44
|
// NOTE: chat.completions has no equivalent slot for replaying reasoning
|
|
39
45
|
// encrypted_content the way the Responses API does (no `type:'reasoning'`
|
|
40
46
|
// input item). Whatever reasoningItems may be attached to assistant
|
|
@@ -421,7 +427,8 @@ export function xaiSystemInstructions(messages) {
|
|
|
421
427
|
return instructions || undefined;
|
|
422
428
|
}
|
|
423
429
|
|
|
424
|
-
export function toXaiResponsesInput(
|
|
430
|
+
export function toXaiResponsesInput(transcript, providerState, options = {}) {
|
|
431
|
+
const messages = withWireToolCallIds(transcript, OPENAI_RESPONSES_TOOL_CALL_IDS);
|
|
425
432
|
const includeSystem = options.includeSystem !== false;
|
|
426
433
|
// Generic Responses callers (opencode-go gateway) keep their own state
|
|
427
434
|
// slot and replay tag so a provider switch never replays foreign items.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Transcript lowering is independent of request/turn metadata. A retained
|
|
2
2
|
// message must have the same wire representation in every subsequent request.
|
|
3
3
|
import { providerReplayItems } from './lib/provider-replay.mjs';
|
|
4
|
+
import { OPENAI_RESPONSES_TOOL_CALL_IDS, withWireToolCallIds } from './lib/tool-call-wire-ids.mjs';
|
|
4
5
|
import { responsesEffortUpdates } from './effort-configuration.mjs';
|
|
5
6
|
import { ensureResponsesCallOutputs } from './lib/wire-pairing.mjs';
|
|
6
7
|
import { normalizeContentForOpenAIResponses, splitToolContentForOpenAIResponses } from './media-normalization.mjs';
|
|
@@ -147,7 +148,8 @@ function pushAssistantToolCalls(toolCalls, { out, customToolCallIds, nativeSearc
|
|
|
147
148
|
* - `includeSystem`, `nativePdf`, `splitToolContent`, `startIndex`: the
|
|
148
149
|
* gateway's system/media/continuation handling.
|
|
149
150
|
*/
|
|
150
|
-
export function convertMessagesToResponsesInput(
|
|
151
|
+
export function convertMessagesToResponsesInput(transcript, opts = {}) {
|
|
152
|
+
const messages = withWireToolCallIds(transcript, OPENAI_RESPONSES_TOOL_CALL_IDS);
|
|
151
153
|
const out = [];
|
|
152
154
|
const pendingToolMedia = [];
|
|
153
155
|
const pendingToolLoads = [];
|