@jmanuelcorral/openteam 0.23.0 → 0.24.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/README.es.md +28 -8
- package/README.md +24 -7
- package/dist/certificates/graph-release-certificate.json +2 -2
- package/dist/certificates/graph-shadow-certificate.json +2 -2
- package/dist/cli/setupAdapters.d.ts +2 -2
- package/dist/cli/setupAdapters.d.ts.map +1 -1
- package/dist/cli.js +955 -380
- package/dist/commands/agents.d.ts +6 -4
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/dispatch.d.ts +1 -1
- package/dist/commands/dispatch.d.ts.map +1 -1
- package/dist/commands/setup.d.ts +22 -33
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1497 -334
- package/dist/local/lemonade.d.ts.map +1 -1
- package/dist/local/lemonadeRequestGuard.d.ts +11 -0
- package/dist/local/lemonadeRequestGuard.d.ts.map +1 -0
- package/dist/local/lemonadeResidency.d.ts +22 -0
- package/dist/local/lemonadeResidency.d.ts.map +1 -0
- package/dist/local/modelResidency.d.ts +4 -0
- package/dist/local/modelResidency.d.ts.map +1 -0
- package/dist/local/slotPool.d.ts +13 -7
- package/dist/local/slotPool.d.ts.map +1 -1
- package/dist/messages/executionSetup.d.ts +19 -2
- package/dist/messages/executionSetup.d.ts.map +1 -1
- package/dist/messages/modelResidency.d.ts +19 -0
- package/dist/messages/modelResidency.d.ts.map +1 -0
- package/dist/messages/orchestration.d.ts +1 -0
- package/dist/messages/orchestration.d.ts.map +1 -1
- package/dist/messages/reload.d.ts +21 -0
- package/dist/messages/reload.d.ts.map +1 -0
- package/dist/opencodeArtifacts/createRosterReload.d.ts +2 -0
- package/dist/opencodeArtifacts/createRosterReload.d.ts.map +1 -0
- package/dist/opencodeArtifacts/orchestratorAgent.d.ts.map +1 -1
- package/dist/opencodeArtifacts/slashCommand.d.ts.map +1 -1
- package/dist/opencodeArtifacts/teamPreparation.d.ts.map +1 -1
- package/dist/orchestrator/coordinator.d.ts.map +1 -1
- package/dist/orchestrator/roster.d.ts +0 -7
- package/dist/orchestrator/roster.d.ts.map +1 -1
- package/dist/orchestrator/runtimeSelection.d.ts +4 -3
- package/dist/orchestrator/runtimeSelection.d.ts.map +1 -1
- package/dist/orchestrator/sessionStatus.d.ts +12 -0
- package/dist/orchestrator/sessionStatus.d.ts.map +1 -0
- package/dist/orchestrator/subsessions.d.ts +2 -10
- package/dist/orchestrator/subsessions.d.ts.map +1 -1
- package/dist/plugin/availability.d.ts +4 -1
- package/dist/plugin/availability.d.ts.map +1 -1
- package/dist/plugin/hooks.d.ts +2 -0
- package/dist/plugin/hooks.d.ts.map +1 -1
- package/dist/plugin/memoryTool.d.ts +9 -3
- package/dist/plugin/memoryTool.d.ts.map +1 -1
- package/dist/plugin/modelResidency.d.ts +47 -0
- package/dist/plugin/modelResidency.d.ts.map +1 -0
- package/dist/plugin/reloadTool.d.ts +33 -0
- package/dist/plugin/reloadTool.d.ts.map +1 -0
- package/dist/router/types.d.ts +2 -0
- package/dist/router/types.d.ts.map +1 -1
- package/dist/telemetry/diagnostics.d.ts +1 -1
- package/dist/telemetry/diagnostics.d.ts.map +1 -1
- package/dist/telemetry/events.d.ts +24 -0
- package/dist/telemetry/events.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4103,6 +4103,28 @@ import { z as z13 } from "zod";
|
|
|
4103
4103
|
// src/telemetry/events.ts
|
|
4104
4104
|
import { z as z11 } from "zod";
|
|
4105
4105
|
|
|
4106
|
+
// src/messages/reload.ts
|
|
4107
|
+
var reloadMessages = {
|
|
4108
|
+
description: "Queue a project-instance reload only after the user explicitly answers the fresh /create_roster reload question affirmatively. General tool approval, YOLO and earlier project-description answers are not consent. End this turn after queuing; do not dispatch work. Cancel withdraws a pending request.",
|
|
4109
|
+
action: "Request a confirmed reload or cancel this session's queued request.",
|
|
4110
|
+
confirmed: "True only for an unambiguous affirmative human answer to the current reload question, after successful preparation and the full Agent/Role/Model and file summaries. This field records consent; it does not independently prove a human answered.",
|
|
4111
|
+
invalid: "Reload not queued: provide only action (request or cancel) and explicit boolean confirmed. No target directory or other arguments are accepted.",
|
|
4112
|
+
declined: "Reload not queued: explicit affirmative consent to the current reload question is required. No files or policies were changed.",
|
|
4113
|
+
denied: "Reload is restricted to the openteam primary in this plugin's project.",
|
|
4114
|
+
closed: "This reload controller is no longer active. Check the current opencode instance before requesting another reload; agent discovery has not been verified.",
|
|
4115
|
+
other: "A reload request is already pending for another session. This call does not replace or extend its confirmation.",
|
|
4116
|
+
authorizing: "Host permission for this project's reload is still pending. This call queues nothing and does not extend the confirmation deadline.",
|
|
4117
|
+
none: "There is no queued reload for this session to cancel.",
|
|
4118
|
+
"reload-queued": "Reload queued, not completed. Waiting up to 30 seconds for this tool and confirming turn to finish and for all project sessions to be idle. End this turn now; no project work or agent readiness is implied.",
|
|
4119
|
+
"reload-waiting": "Reload is still waiting: project sessions are busy or retrying. They will not be aborted; the original 30-second deadline is unchanged.",
|
|
4120
|
+
"reload-accepted": "opencode accepted the project-instance reload request. Agent discovery and readiness have not been verified; existing discovery safeguards still apply.",
|
|
4121
|
+
"reload-cancelled": "The pending reload was cancelled before disposal was requested. Prepared files, history and policies are unchanged.",
|
|
4122
|
+
"reload-timeout": "Reload was not requested: the 30-second idle deadline expired. A new explicit confirmation is required; nothing will retry automatically.",
|
|
4123
|
+
"reload-status-failed": "Reload was not requested: project activity was missing, malformed, unavailable or did not respond within 5 seconds. No idle state was assumed and no automatic retry is armed.",
|
|
4124
|
+
"reload-dispose-failed": "opencode did not confirm acceptance of the reload request. No automatic retry is armed; check the current instance before trying again. Agent readiness is unverified.",
|
|
4125
|
+
"reload-unconfirmed": "Reload acceptance is unconfirmed because the request timed out, was cancelled or the instance was disposed while it was in flight. The host may still finish it; no automatic retry is armed. Check the current instance and agent discovery."
|
|
4126
|
+
};
|
|
4127
|
+
|
|
4106
4128
|
// src/telemetry/diagnostics.ts
|
|
4107
4129
|
var DIAGNOSTIC_CODES = [
|
|
4108
4130
|
"availability-refresh-failed",
|
|
@@ -4115,6 +4137,14 @@ var DIAGNOSTIC_CODES = [
|
|
|
4115
4137
|
"opencode-server-url",
|
|
4116
4138
|
"opencode-version-read-failed",
|
|
4117
4139
|
"privacy-inert",
|
|
4140
|
+
"reload-queued",
|
|
4141
|
+
"reload-waiting",
|
|
4142
|
+
"reload-accepted",
|
|
4143
|
+
"reload-cancelled",
|
|
4144
|
+
"reload-timeout",
|
|
4145
|
+
"reload-status-failed",
|
|
4146
|
+
"reload-dispose-failed",
|
|
4147
|
+
"reload-unconfirmed",
|
|
4118
4148
|
"soak-evidence-rejected",
|
|
4119
4149
|
"telemetry-warning",
|
|
4120
4150
|
"telemetry-write-failed",
|
|
@@ -4142,6 +4172,15 @@ function diagnosticDescription(code) {
|
|
|
4142
4172
|
return "openteam could not read the live opencode version; graph gates fail closed when this happens.";
|
|
4143
4173
|
case "privacy-inert":
|
|
4144
4174
|
return routingMessages.privacyModeDeprecated;
|
|
4175
|
+
case "reload-queued":
|
|
4176
|
+
case "reload-waiting":
|
|
4177
|
+
case "reload-accepted":
|
|
4178
|
+
case "reload-cancelled":
|
|
4179
|
+
case "reload-timeout":
|
|
4180
|
+
case "reload-status-failed":
|
|
4181
|
+
case "reload-dispose-failed":
|
|
4182
|
+
case "reload-unconfirmed":
|
|
4183
|
+
return reloadMessages[code];
|
|
4145
4184
|
case "soak-evidence-rejected":
|
|
4146
4185
|
return "Graph soak evidence contained rejected observation lines; cutover gate evidence may be incomplete.";
|
|
4147
4186
|
case "telemetry-warning":
|
|
@@ -4894,6 +4933,48 @@ function withDeterministicGitLocale(env) {
|
|
|
4894
4933
|
};
|
|
4895
4934
|
}
|
|
4896
4935
|
|
|
4936
|
+
// src/opencodeArtifacts/createRosterReload.ts
|
|
4937
|
+
var CREATE_ROSTER_RELOAD_INSTRUCTIONS = [
|
|
4938
|
+
"## Reload confirmation — /create_roster only",
|
|
4939
|
+
"",
|
|
4940
|
+
"Only after successful persisted registration and verified agent files may you offer reload:",
|
|
4941
|
+
"read back the parseable persisted roster, including guaranteed roles; actually create each missing",
|
|
4942
|
+
"subagent file and verify every required existing or created file.",
|
|
4943
|
+
"First show the complete Agent/Role/Model table returned by `openteam-register-cast`,",
|
|
4944
|
+
"including primary, guaranteed and preserved agents with their unchanged tool-returned policy values.",
|
|
4945
|
+
"Then show the created-versus-preserved file summary and any warnings. Both must be visible",
|
|
4946
|
+
"BEFORE asking a fresh explicit reload question in this opencode conversation.",
|
|
4947
|
+
"If registration, file creation or verification failed or is partial, do not ask the reload question:",
|
|
4948
|
+
"report the exact blocker and do not claim readiness. If registration succeeded, still show its",
|
|
4949
|
+
"complete table even when file preparation later fails.",
|
|
4950
|
+
"",
|
|
4951
|
+
"Ask whether to reload this project's opencode agent definitions now, explaining the request is",
|
|
4952
|
+
"queued/waiting until the requesting turn completes and all project sessions are idle.",
|
|
4953
|
+
"Use the host question tool when available; otherwise ask a normal conversational question",
|
|
4954
|
+
"in opencode and WAIT for the user's answer. Never use a terminal wizard, tool permission",
|
|
4955
|
+
"approval or YOLO permission as reload consent. A greenfield project-description reply is NOT reload consent.",
|
|
4956
|
+
"Only an explicit affirmative answer to this specific reload question authorizes",
|
|
4957
|
+
'`openteam-reload` with `{ action: "request", confirmed: true }`.',
|
|
4958
|
+
"False, no, cancel, an ambiguous answer or no reply means no reload request.",
|
|
4959
|
+
"A decline before anything is queued needs no tool call; do not turn ambiguity into confirmation.",
|
|
4960
|
+
"To cancel an already queued request at the user's direction, use",
|
|
4961
|
+
'`openteam-reload` with `{ action: "cancel", confirmed: false }` and report its actual result.',
|
|
4962
|
+
"",
|
|
4963
|
+
"This internal tool is restricted to the product primary `openteam` and its bound project.",
|
|
4964
|
+
"Do not supply a directory, project, session or other model-selected target.",
|
|
4965
|
+
"Report queued/waiting honestly and end the confirming turn immediately.",
|
|
4966
|
+
"Do not await your own idle state, poll or hold the turn open. Do not start work or call",
|
|
4967
|
+
"`task` or `openteam-orchestrate`; do not rewrite/recast files or change models, permissions",
|
|
4968
|
+
"or execution policies. The idle wait has a finite timeout; surface timeout and failure results",
|
|
4969
|
+
"when the runtime reports them, including rejected requests, rather than promising success or silently retrying.",
|
|
4970
|
+
"SDK acceptance is not verified discovery or readiness. Preserve all existing discovery guards:",
|
|
4971
|
+
"if new agents remain undiscovered, surface the reload/discovery blocker;",
|
|
4972
|
+
"do not dispatch through a generic substitute or claim readiness.",
|
|
4973
|
+
"This workflow and all its replies remain composition only. After completion, decline or cancellation,",
|
|
4974
|
+
"wait for a separate work request; neither a reload answer nor queued acceptance starts project work."
|
|
4975
|
+
].join(`
|
|
4976
|
+
`);
|
|
4977
|
+
|
|
4897
4978
|
// src/opencodeArtifacts/rosterSummary.ts
|
|
4898
4979
|
var ROSTER_SUMMARY_INSTRUCTIONS = [
|
|
4899
4980
|
"After every successful cast creation, repair or extension, show the complete Agent/Role/Model table",
|
|
@@ -4926,6 +5007,20 @@ var TEAM_PREPARATION_INSTRUCTIONS = [
|
|
|
4926
5007
|
"machine bindings stay unchanged; do not require a terminal or manually edit policy to finish hiring.",
|
|
4927
5008
|
"Never infer execution domains from prose, relax permissions, or invent a concrete auto model.",
|
|
4928
5009
|
"Registration/review is idempotent: a capable configured team needs no extra members or file rewrites.",
|
|
5010
|
+
"`agentName`, not `roleID`, determines each worker filename.",
|
|
5011
|
+
"Create `.opencode/agent/<agentName>.md` only for registered roster entries.",
|
|
5012
|
+
"A built-in role profile is not an extra agent.",
|
|
5013
|
+
"Do not create a parallel `<roleID>.md` when the roster maps that role to another alias.",
|
|
5014
|
+
"An existing roster alias equal to its roleID is still valid; do not rename it.",
|
|
5015
|
+
"Do not run `openteam setup` to hire workers or repair their files.",
|
|
5016
|
+
"Preserve unrelated and legacy generic files; do not delete, overwrite or silently register them.",
|
|
5017
|
+
"Registration writes roster/profile state, not worker Markdown.",
|
|
5018
|
+
"Report only verified file changes; do not call pre-existing files newly created.",
|
|
5019
|
+
"When creating a scribe worker, put the following memory instructions in its charter:",
|
|
5020
|
+
"Use `openteam-memory` for durable, reusable facts, entities and typed relations.",
|
|
5021
|
+
"Send only redacted knowledge messages, never raw conversations, prompts or credentials.",
|
|
5022
|
+
"Honor operator permissions and memory settings; do not broaden them.",
|
|
5023
|
+
"A disabled-memory or nothing-recorded result is expected; do not retry it.",
|
|
4929
5024
|
"Create only missing agent definitions; preserve customized files. Show the registration table",
|
|
4930
5025
|
"and verify preparation before dispatch. If opencode cannot discover a new agent, surface",
|
|
4931
5026
|
"the reload/discovery blocker; do not dispatch through a generic substitute or claim readiness."
|
|
@@ -4967,33 +5062,43 @@ function buildOrchestratorAgent(model, options = {}) {
|
|
|
4967
5062
|
"primary agent: there is no pre-created team. You **build the team of",
|
|
4968
5063
|
"subagents on demand** according to the goal of the user and the repository.",
|
|
4969
5064
|
"",
|
|
4970
|
-
"## Golden rule: check the team on EVERY request",
|
|
4971
|
-
"",
|
|
4972
|
-
"Before answering or delegating **any** request, your **first action",
|
|
4973
|
-
"always** is to check whether a team already exists, even if the user does not",
|
|
4974
|
-
"explicitly ask you to create it. Never assume there is a team or that there is not:",
|
|
4975
|
-
`verify it by looking at \`${OPENTEAM_ROSTER_PATH}\` and the \`.opencode/agent/*.md\``,
|
|
4976
|
-
"files with `mode: subagent` (use `read`/`glob`/`list`).",
|
|
4977
|
-
"",
|
|
4978
|
-
ROSTER_SUMMARY_INSTRUCTIONS,
|
|
4979
|
-
"",
|
|
4980
|
-
TEAM_PREPARATION_INSTRUCTIONS,
|
|
4981
|
-
"",
|
|
4982
5065
|
"## Roster composition takes precedence",
|
|
4983
5066
|
"",
|
|
4984
5067
|
"For `/create_roster`, including replies to its pending questions, follow",
|
|
4985
5068
|
"the command's roster-only workflow: do not distribute tasks or start implementation.",
|
|
5069
|
+
"These rules override the ordinary golden rule and capability checks below.",
|
|
5070
|
+
"A bare yes to a pending reload question continues only reload confirmation:",
|
|
5071
|
+
"do not restart roster reads, capability preparation or registration.",
|
|
4986
5072
|
"Reuse or conservatively extend the existing cast and preserve customized agent files.",
|
|
4987
5073
|
"Use a supplied description; otherwise inspect real project source read-only.",
|
|
4988
5074
|
"If there is no meaningful source and no description, ask what the user wants to",
|
|
4989
5075
|
"build in this conversation and wait before any writes or cast registration.",
|
|
4990
5076
|
"Register through `openteam-register-cast`, create missing subagent files, verify",
|
|
4991
|
-
"the persisted roster and files, then
|
|
5077
|
+
"the persisted roster and files, then follow the reload confirmation below.",
|
|
5078
|
+
"Do not call `openteam-orchestrate` or",
|
|
4992
5079
|
"`task` for this workflow. A later answer to your question continues composition",
|
|
4993
5080
|
"only until it completes or the user cancels; it is not an implementation request.",
|
|
4994
5081
|
"",
|
|
5082
|
+
CREATE_ROSTER_RELOAD_INSTRUCTIONS,
|
|
5083
|
+
"",
|
|
5084
|
+
"## Golden rule: check the team on EVERY request",
|
|
5085
|
+
"",
|
|
5086
|
+
"The roster composition and pending reload-reply rules above take precedence.",
|
|
5087
|
+
"Before answering or delegating **any ordinary work** request, your **first action",
|
|
5088
|
+
"always** is to check whether a team already exists, even if the user does not",
|
|
5089
|
+
"explicitly ask you to create it. Never assume there is a team or that there is not:",
|
|
5090
|
+
`verify it by looking at \`${OPENTEAM_ROSTER_PATH}\` and the \`.opencode/agent/*.md\``,
|
|
5091
|
+
"files with `mode: subagent` (use `read`/`glob`/`list`).",
|
|
5092
|
+
"",
|
|
5093
|
+
ROSTER_SUMMARY_INSTRUCTIONS,
|
|
5094
|
+
"",
|
|
5095
|
+
TEAM_PREPARATION_INSTRUCTIONS,
|
|
5096
|
+
"",
|
|
4995
5097
|
"## For work requests, including analysis, review and documentation",
|
|
4996
5098
|
"",
|
|
5099
|
+
"Ordinary automatic hiring must NOT ask for reload or automatically reset the project.",
|
|
5100
|
+
"If discovery is blocked, surface the blocker and preserve the discovery guards instead.",
|
|
5101
|
+
"",
|
|
4997
5102
|
"- **If the team ALREADY exists** → review capability coverage, reuse suitable",
|
|
4998
5103
|
" members and extend only for uncovered needs. Complete any existing member's",
|
|
4999
5104
|
" profile through `openteam-register-cast`; do not hire for a configuration gap.",
|
|
@@ -5368,8 +5473,10 @@ function buildCreateRosterCommand() {
|
|
|
5368
5473
|
"required agent file exists. If anything failed, report the incomplete state and exact",
|
|
5369
5474
|
"blocker; do not delete preserved state or claim the team is ready.",
|
|
5370
5475
|
"Summarize the cast, role rationale/evidence, preserved versus newly created files, and",
|
|
5371
|
-
"any warnings.
|
|
5372
|
-
"
|
|
5476
|
+
"any warnings. Continue only to the reload confirmation below, including its pending replies;",
|
|
5477
|
+
"do not restart preparation when the user answers that reload question.",
|
|
5478
|
+
"",
|
|
5479
|
+
CREATE_ROSTER_RELOAD_INSTRUCTIONS,
|
|
5373
5480
|
"",
|
|
5374
5481
|
"## Project description (user input)",
|
|
5375
5482
|
"",
|
|
@@ -5636,7 +5743,7 @@ import { z as z15 } from "zod";
|
|
|
5636
5743
|
// package.json
|
|
5637
5744
|
var package_default = {
|
|
5638
5745
|
name: "@jmanuelcorral/openteam",
|
|
5639
|
-
version: "0.
|
|
5746
|
+
version: "0.24.1",
|
|
5640
5747
|
packageManager: "bun@1.3.14",
|
|
5641
5748
|
description: "Cost-aware, local-first routing plugin for opencode with cheapest-capable frontier fallback and multi-agent orchestration.",
|
|
5642
5749
|
license: "MIT",
|
|
@@ -5993,6 +6100,25 @@ var executionSetupMessages = {
|
|
|
5993
6100
|
`),
|
|
5994
6101
|
localOnlyTitle: "Local execution",
|
|
5995
6102
|
localRequiredError: "local execution requires an enabled local runtime",
|
|
6103
|
+
lemonadeDetectedHint: (loaded, advertised) => `detected - ${loaded} confirmed loaded of ${advertised} advertised text model(s)`,
|
|
6104
|
+
lemonadeNoLoadedModels: "Lemonade has no text models verified as loaded and ready. Keep the intended model active in Lemonade and rerun setup; inactive or unknown models cannot be selected or entered manually.",
|
|
6105
|
+
lemonadeModelNotLoaded: (model) => `Lemonade model "${model}" is not positively verified as loaded and ready. Keep that exact text model active and rerun setup; no substitute was selected and no implicit loading is allowed.`,
|
|
6106
|
+
lemonadeProbeRequired: "Lemonade setup requires a fresh read-only residency probe before writing configuration. Use the CLI with its runtime probe enabled; manual model IDs cannot bypass this requirement.",
|
|
6107
|
+
lemonadeProbeFailed: "Lemonade residency could not be verified at the configured endpoint. Check connectivity and the read-only /models, /health, and /internal/aliases responses, then rerun setup with the intended text models already active.",
|
|
6108
|
+
lemonadeEndpointMismatch: "Lemonade endpoint/provider mapping differs from the selected runtime. Reconcile the configured base URL and provider before rerunning setup; no model was substituted.",
|
|
6109
|
+
lemonadeModelIdentityUnknown: (model) => `Lemonade model "${model}" has no usable registered wire identity in the effective opencode configuration. Fix its model declaration before rerunning setup; setup will not replace or guess an alias.`,
|
|
6110
|
+
lemonadeEffectiveConfigLabel: "effective setup configuration",
|
|
6111
|
+
lemonadeEffectiveConfigAmbiguous: "Cannot establish one effective openteam configuration from the configured plugin loaders. Reconcile their options before rerunning setup; no provider identity was guessed.",
|
|
6112
|
+
lemonadeRetainedProviderUnprotected: (providerID) => `Cannot safely keep retained Lemonade provider "${providerID}": the effective configuration must retain one matching Lemonade runtime, disabled when deselected. Reconcile the plugin options or machine overlay, or explicitly remove the provider registration before rerunning setup; no configuration was written.`,
|
|
6113
|
+
lemonadeV2InvalidProvider: (providerID) => `Lemonade provider ${JSON.stringify(providerID)} cannot be represented as an exact native V2 policy resource. Choose a non-empty provider ID without wildcards, slashes, backslashes, or whitespace; setup will not broaden a deny rule.`,
|
|
6114
|
+
lemonadeV2InvalidPolicies: "Cannot safely preserve experimental.policies: experimental must be an object and policies must be an array of provider.use statements with a string resource and allow/deny effect. Fix the project configuration before rerunning setup.",
|
|
6115
|
+
lemonadeV2Title: "Lemonade transport compatibility",
|
|
6116
|
+
lemonadeV2Restriction: (providers) => `Project policies disable native V2 Lemonade access for: ${providers.join(", ")}. Ordinary guarded V1 configuration remains supported; V2 is not an openteam-hook execution path. Higher-precedence or global policies can override this project restriction; it is not a server-atomic no-autoload guarantee.`,
|
|
6117
|
+
lemonadeInventory: (instanceID, providerID, models) => {
|
|
6118
|
+
const inventory = models.map((model) => `${model.modelID} (${model.loaded === true ? "loaded" : model.loaded === false ? "inactive" : "residency unknown"})`).join(", ");
|
|
6119
|
+
return `Lemonade inventory ${instanceID} (provider ${providerID}): ${inventory || "no advertised text models"}. Only confirmed loaded text models count as ready.`;
|
|
6120
|
+
},
|
|
6121
|
+
lemonadeAgentResidency: (agent, model, state) => `Lemonade readiness: ${agent} (${model}): ${state === "not-loaded" ? "inactive (not ready)" : "residency unknown"}; advertised inventory is not loaded readiness. Keep this exact model active and verify residency before use; requests without verified readiness are blocked.`,
|
|
5996
6122
|
mixedPrimaryQuestion: "Primary coordinator model",
|
|
5997
6123
|
mixedPrimaryLocal: (model) => `Use local thinking model ${model}`,
|
|
5998
6124
|
mixedPrimaryFrontier: "Choose a frontier model",
|
|
@@ -6015,12 +6141,14 @@ var executionSetupMessages = {
|
|
|
6015
6141
|
`Local runtimes: ${params.localRuntimes}`,
|
|
6016
6142
|
`YOLO mode: ${params.yolo ? "enabled (auto-approves permissions)" : "disabled"}`,
|
|
6017
6143
|
"Web Console: launched separately with 'openteam console' (multi-session, loopback)",
|
|
6018
|
-
`Wrote: ${params.opencodePath}, ${params.configPath}, ${params.agentPath}, ${params.
|
|
6144
|
+
`Wrote: ${params.opencodePath}, ${params.configPath}, ${params.agentPath}, ${params.commandDir}/*.md (${params.commandCount} commands); ensured ${params.gitignorePath}`,
|
|
6145
|
+
"Worker files are created through conversational roster preparation, not setup; existing worker files were left untouched.",
|
|
6019
6146
|
"",
|
|
6020
6147
|
"Next steps:",
|
|
6021
6148
|
params.executionMode === "local" ? " 1. No frontier authentication is required while local execution is active" : " 1. Authenticate the frontier provider: opencode auth login",
|
|
6022
6149
|
params.executionMode === "local" ? executionSetupMessages.localRuntimeNextStep : params.executionMode === "mixed" ? executionSetupMessages.mixedNextStep : executionSetupMessages.frontierNextStep,
|
|
6023
|
-
" 3. Press Tab and pick the 'openteam' agent, or type / and pick an /openteam… command"
|
|
6150
|
+
" 3. Press Tab and pick the 'openteam' agent, or type / and pick an /openteam… command",
|
|
6151
|
+
" 4. Use /create_roster to compose the team without starting project work, or describe a task to prepare the team and begin work"
|
|
6024
6152
|
],
|
|
6025
6153
|
configuredTitle: "openteam configured",
|
|
6026
6154
|
complete: (paths) => `openteam setup complete: ${paths}`,
|
|
@@ -9822,6 +9950,243 @@ function ensureFoundryV1BaseURL(endpoint) {
|
|
|
9822
9950
|
}
|
|
9823
9951
|
}
|
|
9824
9952
|
|
|
9953
|
+
// src/local/lemonadeResidency.ts
|
|
9954
|
+
import { z as z19 } from "zod";
|
|
9955
|
+
|
|
9956
|
+
// src/messages/modelResidency.ts
|
|
9957
|
+
var reasons = {
|
|
9958
|
+
unknown: "fresh residency metadata is unavailable, malformed, or ambiguous",
|
|
9959
|
+
inactive: "the requested model is not verified as resident and serving",
|
|
9960
|
+
identity: "the requested model identity can be rewritten or is ambiguous",
|
|
9961
|
+
destination: "the request destination does not match its configured runtime",
|
|
9962
|
+
transport: "this provider execution path cannot enforce the residency guard",
|
|
9963
|
+
request: "this is not a supported, explicit model inference request",
|
|
9964
|
+
cancelled: "the request was cancelled before residency could be verified",
|
|
9965
|
+
timeout: "the residency metadata deadline expired",
|
|
9966
|
+
configuration: "the residency guard configuration is invalid"
|
|
9967
|
+
};
|
|
9968
|
+
var modelResidencyMessages = {
|
|
9969
|
+
blocked: (reason) => `[openteam] Lemonade model request blocked: ${reasons[reason]}.`,
|
|
9970
|
+
providerDisabled: (providerID) => `[openteam] Lemonade provider "${providerID}" is disabled because its configured transport or runtime mapping cannot enforce loaded-only requests.`,
|
|
9971
|
+
extractionRuntimeUnavailable: "[openteam] Memory extraction requires one enabled local runtime matching the configured extraction provider."
|
|
9972
|
+
};
|
|
9973
|
+
|
|
9974
|
+
// src/local/lemonadeResidency.ts
|
|
9975
|
+
class ModelResidencyError extends Error {
|
|
9976
|
+
code;
|
|
9977
|
+
statusCode = 400;
|
|
9978
|
+
isRetryable = false;
|
|
9979
|
+
constructor(code) {
|
|
9980
|
+
super(modelResidencyMessages.blocked(code));
|
|
9981
|
+
this.code = code;
|
|
9982
|
+
this.name = "ModelResidencyError";
|
|
9983
|
+
}
|
|
9984
|
+
}
|
|
9985
|
+
var modelName = z19.string().min(1).refine((name) => name === name.trim());
|
|
9986
|
+
var LoadedModelSchema = z19.object({
|
|
9987
|
+
model_name: modelName,
|
|
9988
|
+
loaded: z19.boolean().optional(),
|
|
9989
|
+
status: z19.string().optional(),
|
|
9990
|
+
backend_alive: z19.boolean().optional(),
|
|
9991
|
+
backend_health: z19.string().optional(),
|
|
9992
|
+
watchdog_reset: z19.boolean().optional(),
|
|
9993
|
+
watchdog_reset_reason: z19.string().optional(),
|
|
9994
|
+
residency_class: z19.string().optional(),
|
|
9995
|
+
slot_pool: z19.string().optional(),
|
|
9996
|
+
checkpoint: z19.string().optional(),
|
|
9997
|
+
type: z19.string().optional(),
|
|
9998
|
+
device: z19.string().optional(),
|
|
9999
|
+
backend_url: z19.string().optional(),
|
|
10000
|
+
pid: z19.number().int().optional(),
|
|
10001
|
+
launch_command: z19.unknown().optional(),
|
|
10002
|
+
pinned: z19.boolean().optional(),
|
|
10003
|
+
recipe: z19.string().optional(),
|
|
10004
|
+
recipe_options: z19.unknown().optional(),
|
|
10005
|
+
is_busy: z19.boolean().optional(),
|
|
10006
|
+
is_streaming: z19.boolean().optional(),
|
|
10007
|
+
max_context_window: z19.number().optional(),
|
|
10008
|
+
cost_input_per_million: z19.number().optional(),
|
|
10009
|
+
cost_output_per_million: z19.number().optional(),
|
|
10010
|
+
last_use: z19.number().optional()
|
|
10011
|
+
}).strict();
|
|
10012
|
+
var TelemetrySchema = z19.object({
|
|
10013
|
+
enabled: z19.boolean(),
|
|
10014
|
+
captures: z19.array(z19.string()).optional()
|
|
10015
|
+
}).strict();
|
|
10016
|
+
var HealthSchema = z19.object({
|
|
10017
|
+
status: z19.literal("ok"),
|
|
10018
|
+
all_models_loaded: z19.array(LoadedModelSchema),
|
|
10019
|
+
version: z19.string().optional(),
|
|
10020
|
+
model_loaded: z19.string().nullable().optional(),
|
|
10021
|
+
telemetry: TelemetrySchema.optional(),
|
|
10022
|
+
max_models: z19.record(z19.string(), z19.number().int()).optional(),
|
|
10023
|
+
pinned_models: z19.record(z19.string(), z19.number().int()).optional(),
|
|
10024
|
+
pinned_helper_models: z19.record(z19.string(), z19.number().int()).optional(),
|
|
10025
|
+
websocket_port: z19.number().int().optional(),
|
|
10026
|
+
update_check_done: z19.boolean().optional()
|
|
10027
|
+
}).strict();
|
|
10028
|
+
var AliasSchema = z19.object({
|
|
10029
|
+
alias: modelName,
|
|
10030
|
+
target: modelName,
|
|
10031
|
+
downloaded: z19.boolean().optional(),
|
|
10032
|
+
recipe: z19.string().optional()
|
|
10033
|
+
}).strict();
|
|
10034
|
+
var AliasesSchema = z19.object({
|
|
10035
|
+
aliases: z19.array(AliasSchema)
|
|
10036
|
+
}).strict();
|
|
10037
|
+
var MetadataRecordSchema = z19.record(z19.string(), z19.unknown());
|
|
10038
|
+
var inactiveStates = new Set([
|
|
10039
|
+
"loading",
|
|
10040
|
+
"downsizing",
|
|
10041
|
+
"downsized",
|
|
10042
|
+
"evicting",
|
|
10043
|
+
"unloaded"
|
|
10044
|
+
]);
|
|
10045
|
+
var inactiveHealth = new Set(["stopped", "exited", "watchdog_reset"]);
|
|
10046
|
+
var standardPools = new Set([
|
|
10047
|
+
"standard/llm",
|
|
10048
|
+
"standard/embedding",
|
|
10049
|
+
"standard/reranking",
|
|
10050
|
+
"standard/transcription",
|
|
10051
|
+
"standard/image",
|
|
10052
|
+
"standard/tts",
|
|
10053
|
+
"standard/audio-generation",
|
|
10054
|
+
"standard/classification",
|
|
10055
|
+
"standard/mesh"
|
|
10056
|
+
]);
|
|
10057
|
+
function usableState(entry) {
|
|
10058
|
+
if (entry.loaded === false || entry.backend_alive === false || entry.watchdog_reset === true || typeof entry.status === "string" && inactiveStates.has(entry.status) || typeof entry.backend_health === "string" && inactiveHealth.has(entry.backend_health) || entry.residency_class === "routing_helper" || typeof entry.slot_pool === "string" && entry.slot_pool.startsWith("routing_helper/")) {
|
|
10059
|
+
return false;
|
|
10060
|
+
}
|
|
10061
|
+
if (entry.loaded !== true || entry.backend_alive !== true || entry.watchdog_reset !== false || entry.status !== "ready" && entry.status !== "in_use" || entry.backend_health !== "ready" && entry.backend_health !== "busy" || entry.watchdog_reset_reason !== undefined && entry.watchdog_reset_reason !== "" || entry.residency_class !== undefined && entry.residency_class !== "standard" || entry.slot_pool !== undefined && (typeof entry.slot_pool !== "string" || !standardPools.has(entry.slot_pool))) {
|
|
10062
|
+
return;
|
|
10063
|
+
}
|
|
10064
|
+
return true;
|
|
10065
|
+
}
|
|
10066
|
+
function projectMetadataObject(payload, keys) {
|
|
10067
|
+
const record = MetadataRecordSchema.safeParse(payload);
|
|
10068
|
+
if (!record.success)
|
|
10069
|
+
throw new ModelResidencyError("unknown");
|
|
10070
|
+
return Object.fromEntries(keys.filter((key) => Object.hasOwn(record.data, key)).map((key) => [key, record.data[key]]));
|
|
10071
|
+
}
|
|
10072
|
+
function parseResidency(healthPayload, aliasPayload) {
|
|
10073
|
+
const healthFields = projectMetadataObject(healthPayload, Object.keys(HealthSchema.shape));
|
|
10074
|
+
if (Array.isArray(healthFields.all_models_loaded)) {
|
|
10075
|
+
healthFields.all_models_loaded = healthFields.all_models_loaded.map((entry) => projectMetadataObject(entry, Object.keys(LoadedModelSchema.shape)));
|
|
10076
|
+
}
|
|
10077
|
+
if (healthFields.telemetry !== undefined) {
|
|
10078
|
+
healthFields.telemetry = projectMetadataObject(healthFields.telemetry, Object.keys(TelemetrySchema.shape));
|
|
10079
|
+
}
|
|
10080
|
+
const aliasFields = projectMetadataObject(aliasPayload, Object.keys(AliasesSchema.shape));
|
|
10081
|
+
if (Array.isArray(aliasFields.aliases)) {
|
|
10082
|
+
aliasFields.aliases = aliasFields.aliases.map((entry) => projectMetadataObject(entry, Object.keys(AliasSchema.shape)));
|
|
10083
|
+
}
|
|
10084
|
+
const health = HealthSchema.safeParse(healthFields);
|
|
10085
|
+
const aliases = AliasesSchema.safeParse(aliasFields);
|
|
10086
|
+
if (!health.success || !aliases.success)
|
|
10087
|
+
throw new ModelResidencyError("unknown");
|
|
10088
|
+
const result = new Map;
|
|
10089
|
+
for (const entry of health.data.all_models_loaded) {
|
|
10090
|
+
if (result.has(entry.model_name))
|
|
10091
|
+
throw new ModelResidencyError("unknown");
|
|
10092
|
+
result.set(entry.model_name, {
|
|
10093
|
+
loaded: entry.model_name.endsWith(":latest") ? undefined : usableState(entry),
|
|
10094
|
+
metadata: entry
|
|
10095
|
+
});
|
|
10096
|
+
}
|
|
10097
|
+
const seenAliases = new Set;
|
|
10098
|
+
for (const entry of aliases.data.aliases) {
|
|
10099
|
+
if (seenAliases.has(entry.alias))
|
|
10100
|
+
throw new ModelResidencyError("unknown");
|
|
10101
|
+
seenAliases.add(entry.alias);
|
|
10102
|
+
result.set(entry.alias, {
|
|
10103
|
+
loaded: undefined,
|
|
10104
|
+
metadata: result.get(entry.alias)?.metadata ?? {}
|
|
10105
|
+
});
|
|
10106
|
+
}
|
|
10107
|
+
return result;
|
|
10108
|
+
}
|
|
10109
|
+
function lemonadeBaseURL(value) {
|
|
10110
|
+
let url;
|
|
10111
|
+
try {
|
|
10112
|
+
url = new URL(value);
|
|
10113
|
+
} catch {
|
|
10114
|
+
throw new ModelResidencyError("destination");
|
|
10115
|
+
}
|
|
10116
|
+
if (url.protocol !== "http:" && url.protocol !== "https:" || url.username !== "" || url.password !== "" || url.search !== "" || url.hash !== "" || !/^\/(?:api\/)?v[01]\/?$/.test(url.pathname)) {
|
|
10117
|
+
throw new ModelResidencyError("destination");
|
|
10118
|
+
}
|
|
10119
|
+
return `${url.origin}${url.pathname.replace(/\/$/, "")}`;
|
|
10120
|
+
}
|
|
10121
|
+
async function withResidencyDeadline(operation, options) {
|
|
10122
|
+
const timeoutMs = options.timeoutMs ?? 5000;
|
|
10123
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
10124
|
+
throw new ModelResidencyError("configuration");
|
|
10125
|
+
}
|
|
10126
|
+
const controller = new AbortController;
|
|
10127
|
+
const cancel = () => controller.abort(new ModelResidencyError("cancelled"));
|
|
10128
|
+
if (options.signal?.aborted)
|
|
10129
|
+
throw new ModelResidencyError("cancelled");
|
|
10130
|
+
options.signal?.addEventListener("abort", cancel, { once: true });
|
|
10131
|
+
const schedule = options.scheduleTimeout ?? ((callback, ms) => {
|
|
10132
|
+
const timer = setTimeout(callback, ms);
|
|
10133
|
+
return () => clearTimeout(timer);
|
|
10134
|
+
});
|
|
10135
|
+
let onAbort = () => {};
|
|
10136
|
+
const aborted = new Promise((_, reject) => {
|
|
10137
|
+
onAbort = () => reject(controller.signal.reason);
|
|
10138
|
+
controller.signal.addEventListener("abort", onAbort, { once: true });
|
|
10139
|
+
});
|
|
10140
|
+
const clearTimer = schedule(() => controller.abort(new ModelResidencyError("timeout")), timeoutMs);
|
|
10141
|
+
try {
|
|
10142
|
+
controller.signal.throwIfAborted();
|
|
10143
|
+
return await Promise.race([operation(controller.signal), aborted]);
|
|
10144
|
+
} finally {
|
|
10145
|
+
clearTimer();
|
|
10146
|
+
options.signal?.removeEventListener("abort", cancel);
|
|
10147
|
+
controller.signal.removeEventListener("abort", onAbort);
|
|
10148
|
+
controller.abort();
|
|
10149
|
+
}
|
|
10150
|
+
}
|
|
10151
|
+
async function metadata(url, fetch, signal, headers) {
|
|
10152
|
+
signal.throwIfAborted();
|
|
10153
|
+
let payload;
|
|
10154
|
+
try {
|
|
10155
|
+
const response = await fetch(url, {
|
|
10156
|
+
method: "GET",
|
|
10157
|
+
headers,
|
|
10158
|
+
signal,
|
|
10159
|
+
redirect: "error",
|
|
10160
|
+
cache: "no-store"
|
|
10161
|
+
});
|
|
10162
|
+
signal.throwIfAborted();
|
|
10163
|
+
if (!response.ok || response.redirected || response.url !== "" && response.url !== url) {
|
|
10164
|
+
throw new ModelResidencyError("unknown");
|
|
10165
|
+
}
|
|
10166
|
+
payload = await response.json();
|
|
10167
|
+
} catch {
|
|
10168
|
+
signal.throwIfAborted();
|
|
10169
|
+
throw new ModelResidencyError("unknown");
|
|
10170
|
+
}
|
|
10171
|
+
signal.throwIfAborted();
|
|
10172
|
+
return payload;
|
|
10173
|
+
}
|
|
10174
|
+
async function readLemonadeResidency(baseURL, fetch, options = {}) {
|
|
10175
|
+
const base = lemonadeBaseURL(baseURL);
|
|
10176
|
+
const headers = new Headers(options.headers);
|
|
10177
|
+
headers.delete("content-type");
|
|
10178
|
+
headers.delete("content-length");
|
|
10179
|
+
headers.set("accept", "application/json");
|
|
10180
|
+
headers.set("cache-control", "no-cache, no-store");
|
|
10181
|
+
headers.delete("if-none-match");
|
|
10182
|
+
headers.delete("if-modified-since");
|
|
10183
|
+
return withResidencyDeadline(async (signal) => {
|
|
10184
|
+
const aliases = await metadata(`${new URL(base).origin}/internal/aliases`, fetch, signal, headers);
|
|
10185
|
+
const health = await metadata(`${base}/health`, fetch, signal, headers);
|
|
10186
|
+
return parseResidency(health, aliases);
|
|
10187
|
+
}, options);
|
|
10188
|
+
}
|
|
10189
|
+
|
|
9825
10190
|
// src/local/lemonade.ts
|
|
9826
10191
|
var LEMONADE_DEFAULT_BASE_URL = "http://localhost:13305/api/v1";
|
|
9827
10192
|
var NON_TEXT_LABELS = new Set([
|
|
@@ -9908,36 +10273,19 @@ function isNonTextModel(entry) {
|
|
|
9908
10273
|
return entry.labels.some((label) => typeof label === "string" && NON_TEXT_LABELS.has(label));
|
|
9909
10274
|
}
|
|
9910
10275
|
async function readLoadedModels(baseURL, fetch) {
|
|
9911
|
-
let payload;
|
|
9912
10276
|
try {
|
|
9913
|
-
const
|
|
9914
|
-
|
|
9915
|
-
|
|
9916
|
-
|
|
9917
|
-
|
|
9918
|
-
|
|
9919
|
-
|
|
9920
|
-
|
|
10277
|
+
const residency = await readLemonadeResidency(baseURL, fetch);
|
|
10278
|
+
return new Map([...residency].map(([name, entry]) => [
|
|
10279
|
+
name,
|
|
10280
|
+
{
|
|
10281
|
+
loaded: entry.loaded,
|
|
10282
|
+
slots: entry.loaded === true ? readSlotCount(entry.metadata) : undefined,
|
|
10283
|
+
totalContextWindow: entry.loaded === true ? readLoadedContextWindow(entry.metadata) : undefined
|
|
10284
|
+
}
|
|
10285
|
+
]));
|
|
9921
10286
|
} catch {
|
|
9922
10287
|
return;
|
|
9923
10288
|
}
|
|
9924
|
-
if (!isObject2(payload) || !Array.isArray(payload.all_models_loaded)) {
|
|
9925
|
-
return;
|
|
9926
|
-
}
|
|
9927
|
-
const loaded = new Map;
|
|
9928
|
-
for (const entry of payload.all_models_loaded) {
|
|
9929
|
-
if (!isObject2(entry) || typeof entry.model_name !== "string") {
|
|
9930
|
-
continue;
|
|
9931
|
-
}
|
|
9932
|
-
if (entry.loaded === false) {
|
|
9933
|
-
continue;
|
|
9934
|
-
}
|
|
9935
|
-
loaded.set(entry.model_name, {
|
|
9936
|
-
slots: readSlotCount(entry),
|
|
9937
|
-
totalContextWindow: readLoadedContextWindow(entry)
|
|
9938
|
-
});
|
|
9939
|
-
}
|
|
9940
|
-
return loaded;
|
|
9941
10289
|
}
|
|
9942
10290
|
function readSlotCount(entry) {
|
|
9943
10291
|
return slotsFromLlamacppArgs(entry) ?? slotsFromLaunchCommand(entry);
|
|
@@ -10084,6 +10432,9 @@ function enrichWithLoadState(models, loaded) {
|
|
|
10084
10432
|
if (hit === undefined) {
|
|
10085
10433
|
return { ...base, loaded: false };
|
|
10086
10434
|
}
|
|
10435
|
+
if (hit.loaded !== true) {
|
|
10436
|
+
return hit.loaded === false ? { ...base, loaded: false } : base;
|
|
10437
|
+
}
|
|
10087
10438
|
const contextWindow = derivedConservativeContextWindow(model.contextWindow, hit);
|
|
10088
10439
|
return {
|
|
10089
10440
|
...base,
|
|
@@ -10227,6 +10578,14 @@ function reportedModelSlotsByRuntime(snapshots) {
|
|
|
10227
10578
|
}
|
|
10228
10579
|
|
|
10229
10580
|
// src/local/slotPool.ts
|
|
10581
|
+
function localModelAliases(providerID, models) {
|
|
10582
|
+
const aliases = new Map;
|
|
10583
|
+
for (const model of models ?? []) {
|
|
10584
|
+
if (model.kind === "local" && model.providerID === providerID && model.runtimeModelID !== undefined && model.runtimeModelID !== model.modelID)
|
|
10585
|
+
aliases.set(model.modelID, model.runtimeModelID);
|
|
10586
|
+
}
|
|
10587
|
+
return aliases;
|
|
10588
|
+
}
|
|
10230
10589
|
var POOL_SEPARATOR = "::";
|
|
10231
10590
|
function slotPoolKey(runtime, modelID) {
|
|
10232
10591
|
if (modelID === undefined) {
|
|
@@ -10256,13 +10615,20 @@ function slotPoolReservedInteractive(runtime, modelID) {
|
|
|
10256
10615
|
function unknownPoolCapacity() {
|
|
10257
10616
|
return DEFAULT_LOCAL_MAX_CONCURRENCY;
|
|
10258
10617
|
}
|
|
10259
|
-
function withReportedModelSlots(runtime, reported) {
|
|
10260
|
-
|
|
10618
|
+
function withReportedModelSlots(runtime, reported, aliases) {
|
|
10619
|
+
const configured = Object.entries(runtime.modelConcurrency ?? {});
|
|
10620
|
+
const hasAliasLimits = configured.some(([modelID]) => aliases?.has(modelID) === true);
|
|
10621
|
+
if (!hasAliasLimits && (reported === undefined || Object.keys(reported).length === 0)) {
|
|
10261
10622
|
return runtime;
|
|
10262
10623
|
}
|
|
10624
|
+
const explicit = new Map;
|
|
10625
|
+
for (const [modelID, limit] of configured) {
|
|
10626
|
+
const physicalID = aliases?.get(modelID) ?? modelID;
|
|
10627
|
+
explicit.set(physicalID, Math.min(explicit.get(physicalID) ?? limit, limit));
|
|
10628
|
+
}
|
|
10263
10629
|
return {
|
|
10264
10630
|
...runtime,
|
|
10265
|
-
modelConcurrency: { ...reported, ...
|
|
10631
|
+
modelConcurrency: { ...reported, ...Object.fromEntries(explicit) }
|
|
10266
10632
|
};
|
|
10267
10633
|
}
|
|
10268
10634
|
|
|
@@ -10294,8 +10660,11 @@ var UNAUTHORIZED_MODEL_SWITCH_REASON = "routing-model-switch-not-authorized";
|
|
|
10294
10660
|
function invalidRoleIdentifier(roleID) {
|
|
10295
10661
|
return `invalid role identifier "${roleID}" — use letters, numbers, underscores, or hyphens, starting with a letter or number`;
|
|
10296
10662
|
}
|
|
10663
|
+
function agentPreparationRemedy(agentName) {
|
|
10664
|
+
return "Use `/create_roster` in opencode to complete the missing roster agent " + "definitions without changing existing aliases. " + `If \`.opencode/agent/${agentName}.md\` already exists, reload opencode ` + "to discover it before retrying; do not substitute an unrelated agent.";
|
|
10665
|
+
}
|
|
10297
10666
|
function missingAgentDefinition(agentName, roleID) {
|
|
10298
|
-
return `agent definition "${agentName}" is not installed for role "${roleID}". ` +
|
|
10667
|
+
return `agent definition "${agentName}" is not installed for role "${roleID}". ` + agentPreparationRemedy(agentName);
|
|
10299
10668
|
}
|
|
10300
10669
|
function dependencyValidationError(code, detail) {
|
|
10301
10670
|
return `dependency validation error: ${code} (${detail})`;
|
|
@@ -10356,14 +10725,14 @@ var readReportArtifact = async (reportPath) => {
|
|
|
10356
10725
|
};
|
|
10357
10726
|
|
|
10358
10727
|
// src/orchestrator/roster.ts
|
|
10359
|
-
import { z as
|
|
10360
|
-
var RosterEntrySchema =
|
|
10361
|
-
roleID:
|
|
10362
|
-
agentName:
|
|
10728
|
+
import { z as z20 } from "zod";
|
|
10729
|
+
var RosterEntrySchema = z20.object({
|
|
10730
|
+
roleID: z20.string().min(1),
|
|
10731
|
+
agentName: z20.string().min(1)
|
|
10363
10732
|
}).strict();
|
|
10364
|
-
var RosterSchema =
|
|
10365
|
-
universe:
|
|
10366
|
-
entries:
|
|
10733
|
+
var RosterSchema = z20.object({
|
|
10734
|
+
universe: z20.string().min(1),
|
|
10735
|
+
entries: z20.array(RosterEntrySchema)
|
|
10367
10736
|
}).strict();
|
|
10368
10737
|
var ROSTER_JSON_FENCE = /```json\s*([\s\S]*?)```/;
|
|
10369
10738
|
|
|
@@ -10548,6 +10917,50 @@ function lifecycleRecordingAdvisory(status) {
|
|
|
10548
10917
|
return `Lifecycle history recording is ${status.state}${failure}; model execution continued without claiming complete history.`;
|
|
10549
10918
|
}
|
|
10550
10919
|
|
|
10920
|
+
// src/orchestrator/sessionStatus.ts
|
|
10921
|
+
function dataProperties(value) {
|
|
10922
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
10923
|
+
return;
|
|
10924
|
+
try {
|
|
10925
|
+
const prototype = Object.getPrototypeOf(value);
|
|
10926
|
+
if (prototype !== Object.prototype && prototype !== null)
|
|
10927
|
+
return;
|
|
10928
|
+
if (Reflect.ownKeys(value).some((key) => typeof key !== "string"))
|
|
10929
|
+
return;
|
|
10930
|
+
const properties = Object.getOwnPropertyDescriptors(value);
|
|
10931
|
+
return Object.values(properties).every((property) => ("value" in property) && property.enumerable === true) ? properties : undefined;
|
|
10932
|
+
} catch {
|
|
10933
|
+
return;
|
|
10934
|
+
}
|
|
10935
|
+
}
|
|
10936
|
+
function parseSessionStatus(value) {
|
|
10937
|
+
const properties = dataProperties(value);
|
|
10938
|
+
if (properties === undefined)
|
|
10939
|
+
return;
|
|
10940
|
+
const type = properties.type?.value;
|
|
10941
|
+
if (type === "idle" || type === "busy")
|
|
10942
|
+
return { type };
|
|
10943
|
+
const attempt = properties.attempt?.value;
|
|
10944
|
+
const message = properties.message?.value;
|
|
10945
|
+
const next = properties.next?.value;
|
|
10946
|
+
if (type === "retry" && typeof attempt === "number" && Number.isFinite(attempt) && typeof message === "string" && typeof next === "number" && Number.isFinite(next))
|
|
10947
|
+
return { type, attempt, message, next };
|
|
10948
|
+
return;
|
|
10949
|
+
}
|
|
10950
|
+
function parseSessionStatusMap(value) {
|
|
10951
|
+
const properties = dataProperties(value);
|
|
10952
|
+
if (properties === undefined)
|
|
10953
|
+
return;
|
|
10954
|
+
const entries = [];
|
|
10955
|
+
for (const [sessionID, property] of Object.entries(properties)) {
|
|
10956
|
+
const status = parseSessionStatus(property.value);
|
|
10957
|
+
if (status === undefined)
|
|
10958
|
+
return;
|
|
10959
|
+
entries.push([sessionID, status]);
|
|
10960
|
+
}
|
|
10961
|
+
return Object.fromEntries(entries);
|
|
10962
|
+
}
|
|
10963
|
+
|
|
10551
10964
|
// src/orchestrator/subsessions.ts
|
|
10552
10965
|
var DEFAULT_ABORT_GRACE_MS = 2000;
|
|
10553
10966
|
var DEFAULT_STATUS_POLL_MS = 100;
|
|
@@ -10773,28 +11186,6 @@ function statusArgs(directory, signal) {
|
|
|
10773
11186
|
function abortArgs(sessionID, directory, signal) {
|
|
10774
11187
|
return directory === undefined ? { path: { id: sessionID }, signal } : { path: { id: sessionID }, query: { directory }, signal };
|
|
10775
11188
|
}
|
|
10776
|
-
function isSessionStatus(value) {
|
|
10777
|
-
if (!isObject3(value))
|
|
10778
|
-
return false;
|
|
10779
|
-
const type = safeGet(value, "type");
|
|
10780
|
-
if (type === "idle" || type === "busy")
|
|
10781
|
-
return true;
|
|
10782
|
-
if (type !== "retry")
|
|
10783
|
-
return false;
|
|
10784
|
-
return typeof safeGet(value, "attempt") === "number" && typeof safeGet(value, "message") === "string" && typeof safeGet(value, "next") === "number";
|
|
10785
|
-
}
|
|
10786
|
-
function isSessionStatusMap(value) {
|
|
10787
|
-
if (!isObject3(value) || Array.isArray(value))
|
|
10788
|
-
return false;
|
|
10789
|
-
try {
|
|
10790
|
-
const prototype = Object.getPrototypeOf(value);
|
|
10791
|
-
if (prototype !== Object.prototype && prototype !== null)
|
|
10792
|
-
return false;
|
|
10793
|
-
return Object.values(value).every(isSessionStatus);
|
|
10794
|
-
} catch {
|
|
10795
|
-
return false;
|
|
10796
|
-
}
|
|
10797
|
-
}
|
|
10798
11189
|
async function confirmSessionStopped(client, sessionID, directory, deps, deadline) {
|
|
10799
11190
|
const abortSession = client.session.abort;
|
|
10800
11191
|
if (abortSession === undefined) {
|
|
@@ -10843,8 +11234,8 @@ async function confirmSessionStopped(client, sessionID, directory, deps, deadlin
|
|
|
10843
11234
|
if (safeGet(statuses, "error") !== undefined) {
|
|
10844
11235
|
return { confirmed: false, cause: "status-error" };
|
|
10845
11236
|
}
|
|
10846
|
-
const snapshot = safeGet(statuses, "data");
|
|
10847
|
-
if (
|
|
11237
|
+
const snapshot = parseSessionStatusMap(safeGet(statuses, "data"));
|
|
11238
|
+
if (snapshot === undefined) {
|
|
10848
11239
|
return { confirmed: false, cause: "status-missing" };
|
|
10849
11240
|
}
|
|
10850
11241
|
if (!Object.hasOwn(snapshot, sessionID)) {
|
|
@@ -10986,10 +11377,21 @@ async function runSubsession(client, req, deps) {
|
|
|
10986
11377
|
}
|
|
10987
11378
|
}
|
|
10988
11379
|
|
|
11380
|
+
// src/local/modelResidency.ts
|
|
11381
|
+
function hasRequiredModelResidency(kind, model) {
|
|
11382
|
+
return kind !== "lemonade" || model?.loaded === true;
|
|
11383
|
+
}
|
|
11384
|
+
|
|
10989
11385
|
// src/plugin/availability.ts
|
|
10990
11386
|
function modelKey2(model) {
|
|
10991
11387
|
return `${model.providerID}/${model.modelID}`;
|
|
10992
11388
|
}
|
|
11389
|
+
function availabilityMetadata({
|
|
11390
|
+
apiModelID: _apiModelID,
|
|
11391
|
+
...metadata2
|
|
11392
|
+
}) {
|
|
11393
|
+
return metadata2;
|
|
11394
|
+
}
|
|
10993
11395
|
function compareAvailableModels(left, right) {
|
|
10994
11396
|
const kindOrder = Number(left.kind === "frontier") - Number(right.kind === "frontier");
|
|
10995
11397
|
if (kindOrder !== 0) {
|
|
@@ -11007,6 +11409,9 @@ function uniqueSelections(models) {
|
|
|
11007
11409
|
function isConfiguredLocalModel(config, model) {
|
|
11008
11410
|
return config.local.runtimes.some((runtime) => runtime.defaultModel.providerID === model.providerID);
|
|
11009
11411
|
}
|
|
11412
|
+
function requiresModelResidency(config, model) {
|
|
11413
|
+
return config.local.runtimes.some((runtime) => runtime.defaultModel.providerID === model.providerID && !hasRequiredModelResidency(localRuntimeKind(runtime), undefined));
|
|
11414
|
+
}
|
|
11010
11415
|
function configuredFrontierProviderIDs(config) {
|
|
11011
11416
|
const providerIDs = new Set([config.baseline.hardDefault.providerID]);
|
|
11012
11417
|
if (config.baseline.mode === "pinned" && config.baseline.pinnedModel !== null) {
|
|
@@ -11101,7 +11506,7 @@ function frontierAvailableModels(config, configuredModels) {
|
|
|
11101
11506
|
for (const model of configuredModels ?? frontierBaselines(config)) {
|
|
11102
11507
|
if (!isConfiguredLocalModel(config, model)) {
|
|
11103
11508
|
frontierByKey.set(modelKey2(model), {
|
|
11104
|
-
...model,
|
|
11509
|
+
...availabilityMetadata(model),
|
|
11105
11510
|
kind: "frontier",
|
|
11106
11511
|
available: true
|
|
11107
11512
|
});
|
|
@@ -11117,7 +11522,7 @@ function defaultAvailableModels(config, configuredModels) {
|
|
|
11117
11522
|
...defaultLocalModels(config).map((model) => ({
|
|
11118
11523
|
...model,
|
|
11119
11524
|
kind: "local",
|
|
11120
|
-
available:
|
|
11525
|
+
available: !requiresModelResidency(config, model)
|
|
11121
11526
|
})),
|
|
11122
11527
|
...frontierAvailableModels(config, configuredModels)
|
|
11123
11528
|
].sort(compareAvailableModels);
|
|
@@ -11131,7 +11536,8 @@ function toAvailableModels(snapshots, config, configuredModels) {
|
|
|
11131
11536
|
continue;
|
|
11132
11537
|
}
|
|
11133
11538
|
localByKey.set(modelKey2(model), {
|
|
11134
|
-
...model,
|
|
11539
|
+
...availabilityMetadata(model),
|
|
11540
|
+
...model.apiModelID !== undefined && model.apiModelID !== model.modelID ? { runtimeModelID: model.apiModelID } : {},
|
|
11135
11541
|
kind: "local",
|
|
11136
11542
|
available: false
|
|
11137
11543
|
});
|
|
@@ -11142,27 +11548,25 @@ function toAvailableModels(snapshots, config, configuredModels) {
|
|
|
11142
11548
|
continue;
|
|
11143
11549
|
}
|
|
11144
11550
|
for (const model of snapshot.models) {
|
|
11145
|
-
const
|
|
11146
|
-
|
|
11147
|
-
|
|
11148
|
-
|
|
11149
|
-
|
|
11150
|
-
|
|
11151
|
-
|
|
11152
|
-
|
|
11153
|
-
|
|
11154
|
-
|
|
11155
|
-
|
|
11156
|
-
|
|
11157
|
-
|
|
11158
|
-
|
|
11159
|
-
|
|
11160
|
-
|
|
11161
|
-
|
|
11162
|
-
|
|
11163
|
-
availableModel.contextWindow = model.contextWindow;
|
|
11551
|
+
const providerID = runtime.defaultModel.providerID;
|
|
11552
|
+
const refs = configuredModels === undefined ? [{ providerID, modelID: model.modelID }] : configuredModels.filter((registered) => registered.providerID === providerID && (registered.apiModelID ?? registered.modelID) === model.modelID);
|
|
11553
|
+
for (const ref of refs) {
|
|
11554
|
+
const existing = localByKey.get(modelKey2(ref));
|
|
11555
|
+
const availableModel = {
|
|
11556
|
+
...existing,
|
|
11557
|
+
providerID: ref.providerID,
|
|
11558
|
+
modelID: ref.modelID,
|
|
11559
|
+
kind: "local",
|
|
11560
|
+
available: snapshot.reachable && hasRequiredModelResidency(localRuntimeKind(runtime), model) || existing?.available === true
|
|
11561
|
+
};
|
|
11562
|
+
if (model.supportsTools !== "unknown") {
|
|
11563
|
+
availableModel.supportsTools = model.supportsTools;
|
|
11564
|
+
}
|
|
11565
|
+
if (model.contextWindow !== undefined) {
|
|
11566
|
+
availableModel.contextWindow = model.contextWindow;
|
|
11567
|
+
}
|
|
11568
|
+
localByKey.set(modelKey2(ref), availableModel);
|
|
11164
11569
|
}
|
|
11165
|
-
localByKey.set(modelKey2(ref), availableModel);
|
|
11166
11570
|
}
|
|
11167
11571
|
}
|
|
11168
11572
|
return [
|
|
@@ -11171,7 +11575,7 @@ function toAvailableModels(snapshots, config, configuredModels) {
|
|
|
11171
11575
|
].sort(compareAvailableModels);
|
|
11172
11576
|
}
|
|
11173
11577
|
function createAvailabilityCache(options) {
|
|
11174
|
-
let configuredModels = options.initialConfiguredModels === undefined ? undefined :
|
|
11578
|
+
let configuredModels = options.initialConfiguredModels === undefined ? undefined : options.initialConfiguredModels.map((model) => ({ ...model }));
|
|
11175
11579
|
let configuredProfiles = (options.initialConfiguredProfiles ?? []).map((profile) => profileForConfiguredDomain(options.config, profile));
|
|
11176
11580
|
let cached = defaultAvailableModels(options.config, configuredModels);
|
|
11177
11581
|
let inFlight;
|
|
@@ -11181,7 +11585,9 @@ function createAvailabilityCache(options) {
|
|
|
11181
11585
|
if (options.listConfiguredInventory !== undefined) {
|
|
11182
11586
|
const inventory = await options.listConfiguredInventory().then((value) => ({ kind: "models", value }), (error) => ({ kind: "error", error }));
|
|
11183
11587
|
if (inventory.kind === "models") {
|
|
11184
|
-
configuredModels = inventory.value.models
|
|
11588
|
+
configuredModels = inventory.value.models.map((model) => ({
|
|
11589
|
+
...model
|
|
11590
|
+
}));
|
|
11185
11591
|
configuredProfiles = inventory.value.profiles.map((profile) => profileForConfiguredDomain(options.config, profile));
|
|
11186
11592
|
} else {
|
|
11187
11593
|
options.onRefreshError?.(inventory.error);
|
|
@@ -11194,15 +11600,22 @@ function createAvailabilityCache(options) {
|
|
|
11194
11600
|
}
|
|
11195
11601
|
return {
|
|
11196
11602
|
get: () => cloneAvailableModels(cached),
|
|
11603
|
+
resolveApiModelID: (ref) => {
|
|
11604
|
+
const registered = configuredModels?.find((model) => model.providerID === ref.providerID && model.modelID === ref.modelID);
|
|
11605
|
+
return registered?.apiModelID ?? registered?.modelID;
|
|
11606
|
+
},
|
|
11197
11607
|
getProfiles: () => configuredProfiles.map((profile) => ({
|
|
11198
11608
|
...profile,
|
|
11199
11609
|
ref: { ...profile.ref },
|
|
11200
11610
|
costPer1M: { ...profile.costPer1M }
|
|
11201
11611
|
})),
|
|
11202
11612
|
refresh: () => {
|
|
11203
|
-
inFlight
|
|
11204
|
-
|
|
11205
|
-
|
|
11613
|
+
if (inFlight === undefined) {
|
|
11614
|
+
cached = cached.map((model) => requiresModelResidency(options.config, model) ? { ...model, available: false } : model);
|
|
11615
|
+
inFlight = refreshNow().finally(() => {
|
|
11616
|
+
inFlight = undefined;
|
|
11617
|
+
});
|
|
11618
|
+
}
|
|
11206
11619
|
return inFlight;
|
|
11207
11620
|
}
|
|
11208
11621
|
};
|
|
@@ -11370,7 +11783,7 @@ function planWorktreeReconciliation(input) {
|
|
|
11370
11783
|
}
|
|
11371
11784
|
|
|
11372
11785
|
// src/telemetry/otelConfig.ts
|
|
11373
|
-
import { z as
|
|
11786
|
+
import { z as z21 } from "zod";
|
|
11374
11787
|
|
|
11375
11788
|
// src/telemetry/fanout.ts
|
|
11376
11789
|
function createFanOutSink(deps) {
|
|
@@ -11448,10 +11861,10 @@ function createOtelSink(deps) {
|
|
|
11448
11861
|
}
|
|
11449
11862
|
|
|
11450
11863
|
// src/telemetry/otelConfig.ts
|
|
11451
|
-
var OtelBackendConfigSchema =
|
|
11452
|
-
backend:
|
|
11453
|
-
connectionEnv:
|
|
11454
|
-
serviceName:
|
|
11864
|
+
var OtelBackendConfigSchema = z21.object({
|
|
11865
|
+
backend: z21.literal("opentelemetry"),
|
|
11866
|
+
connectionEnv: z21.string().min(1),
|
|
11867
|
+
serviceName: z21.string().min(1).optional()
|
|
11455
11868
|
}).strict();
|
|
11456
11869
|
function parseConnectionString(raw) {
|
|
11457
11870
|
const pairs = new Map;
|
|
@@ -11876,7 +12289,7 @@ function parseOpencodeProviders(opencodeConfig) {
|
|
|
11876
12289
|
function localRuntimeStates(config) {
|
|
11877
12290
|
const map = new Map;
|
|
11878
12291
|
for (const runtime of config.local.runtimes) {
|
|
11879
|
-
map.set(runtime.
|
|
12292
|
+
map.set(runtime.defaultModel.providerID, { enabled: runtime.enabled });
|
|
11880
12293
|
}
|
|
11881
12294
|
return map;
|
|
11882
12295
|
}
|
|
@@ -11884,7 +12297,7 @@ function disabledLocalProviderIDs(config) {
|
|
|
11884
12297
|
const ids = new Set;
|
|
11885
12298
|
for (const runtime of config.local.runtimes) {
|
|
11886
12299
|
if (!runtime.enabled) {
|
|
11887
|
-
ids.add(runtime.
|
|
12300
|
+
ids.add(runtime.defaultModel.providerID);
|
|
11888
12301
|
}
|
|
11889
12302
|
}
|
|
11890
12303
|
return ids;
|
|
@@ -11900,7 +12313,11 @@ function computeLive(model, isLocalProvider, liveModels) {
|
|
|
11900
12313
|
if (!snapshot.reachable) {
|
|
11901
12314
|
return "unreachable";
|
|
11902
12315
|
}
|
|
11903
|
-
|
|
12316
|
+
if (snapshot.modelIDs.has(model.modelID))
|
|
12317
|
+
return "confirmed";
|
|
12318
|
+
if (snapshot.residency?.has(model.modelID))
|
|
12319
|
+
return snapshot.residency.get(model.modelID) === false ? "not-loaded" : "residency-unknown";
|
|
12320
|
+
return "not-advertised";
|
|
11904
12321
|
}
|
|
11905
12322
|
function resolveAgentModel(model, context) {
|
|
11906
12323
|
const isLocalProvider = KNOWN_LOCAL_PROVIDER_IDS.has(model.providerID) || context.localRuntimes.has(model.providerID);
|
|
@@ -13174,7 +13591,6 @@ var GENERATED_OPENTEAM_STATE_GROUPS = [
|
|
|
13174
13591
|
{ kind: "file", paths: [SOAK_RECORDER_ID_PATH] }
|
|
13175
13592
|
];
|
|
13176
13593
|
var OPENCODE_DIR = ".opencode";
|
|
13177
|
-
var AGENT_DIR = `${OPENCODE_DIR}/agent`;
|
|
13178
13594
|
function splitSetupPath(path3) {
|
|
13179
13595
|
return path3.split("/").filter((segment) => segment.length > 0);
|
|
13180
13596
|
}
|
|
@@ -14232,12 +14648,19 @@ function defaultModelFromOpencode(opencodeConfig) {
|
|
|
14232
14648
|
}
|
|
14233
14649
|
return;
|
|
14234
14650
|
}
|
|
14235
|
-
function liveModelsFromSnapshots(snapshots) {
|
|
14651
|
+
function liveModelsFromSnapshots(snapshots, config) {
|
|
14236
14652
|
const map = new Map;
|
|
14237
14653
|
for (const snapshot of snapshots) {
|
|
14238
|
-
|
|
14654
|
+
const runtime = config.local.runtimes.find((runtime2) => runtime2.id === snapshot.id);
|
|
14655
|
+
if (runtime === undefined || !runtime.enabled)
|
|
14656
|
+
continue;
|
|
14657
|
+
const kind = localRuntimeKind(runtime);
|
|
14658
|
+
map.set(runtime.defaultModel.providerID, {
|
|
14239
14659
|
reachable: snapshot.reachable,
|
|
14240
|
-
modelIDs: new Set(snapshot.models.map((model) => model.modelID))
|
|
14660
|
+
modelIDs: new Set(snapshot.models.filter((model) => hasRequiredModelResidency(kind, model)).map((model) => model.modelID)),
|
|
14661
|
+
...kind === "lemonade" ? {
|
|
14662
|
+
residency: new Map(snapshot.models.map((model) => [model.modelID, model.loaded]))
|
|
14663
|
+
} : {}
|
|
14241
14664
|
});
|
|
14242
14665
|
}
|
|
14243
14666
|
return map;
|
|
@@ -14523,7 +14946,7 @@ async function runCli(argv, deps) {
|
|
|
14523
14946
|
const agentModels = diagnoseAgentModels(agentFiles, {
|
|
14524
14947
|
opencodeProviders: parseOpencodeProviders(opencodeConfig),
|
|
14525
14948
|
localRuntimes: localRuntimeStates(config),
|
|
14526
|
-
liveModels: liveModelsFromSnapshots(snapshots),
|
|
14949
|
+
liveModels: liveModelsFromSnapshots(snapshots, config),
|
|
14527
14950
|
sourceDir: deps.agentDir,
|
|
14528
14951
|
...defaultModel !== undefined ? { defaultModel } : {}
|
|
14529
14952
|
});
|
|
@@ -14562,29 +14985,53 @@ async function runCli(argv, deps) {
|
|
|
14562
14985
|
const rosterMissing = deps.loadRosterForDoctor !== undefined && roster === undefined && rosterLoadError === undefined;
|
|
14563
14986
|
const orchestratorAgentName = ORCHESTRATOR_AGENT_PATH.slice(ORCHESTRATOR_AGENT_PATH.lastIndexOf("/") + 1).replace(/\.md$/, "");
|
|
14564
14987
|
const orchestratorAgentMissing = !agentFiles.some((file) => file.name === orchestratorAgentName);
|
|
14988
|
+
const inventoryNotes = [];
|
|
14989
|
+
const readySnapshots = snapshots.map((snapshot) => {
|
|
14990
|
+
const runtime = config.local.runtimes.find((runtime2) => runtime2.id === snapshot.id);
|
|
14991
|
+
if (runtime === undefined || localRuntimeKind(runtime) !== "lemonade")
|
|
14992
|
+
return snapshot;
|
|
14993
|
+
inventoryNotes.push(executionSetupMessages.lemonadeInventory(runtime.id, runtime.defaultModel.providerID, snapshot.models));
|
|
14994
|
+
return {
|
|
14995
|
+
...snapshot,
|
|
14996
|
+
models: snapshot.models.filter((model) => hasRequiredModelResidency(localRuntimeKind(runtime), model))
|
|
14997
|
+
};
|
|
14998
|
+
});
|
|
14999
|
+
const residencyNotes = agentModels.flatMap((agent) => {
|
|
15000
|
+
const live = agent.resolution?.live;
|
|
15001
|
+
if (agent.model === undefined || live !== "not-loaded" && live !== "residency-unknown")
|
|
15002
|
+
return [];
|
|
15003
|
+
return [
|
|
15004
|
+
executionSetupMessages.lemonadeAgentResidency(agent.name, `${agent.model.providerID}/${agent.model.modelID}`, live)
|
|
15005
|
+
];
|
|
15006
|
+
});
|
|
14565
15007
|
return {
|
|
14566
15008
|
exitCode: 0,
|
|
14567
|
-
stdout:
|
|
14568
|
-
|
|
14569
|
-
|
|
14570
|
-
|
|
14571
|
-
|
|
14572
|
-
|
|
14573
|
-
|
|
14574
|
-
|
|
14575
|
-
|
|
14576
|
-
|
|
14577
|
-
|
|
14578
|
-
|
|
14579
|
-
|
|
14580
|
-
|
|
14581
|
-
|
|
14582
|
-
|
|
14583
|
-
|
|
14584
|
-
|
|
14585
|
-
|
|
14586
|
-
|
|
14587
|
-
|
|
15009
|
+
stdout: [
|
|
15010
|
+
renderDoctor({
|
|
15011
|
+
config,
|
|
15012
|
+
snapshots: readySnapshots,
|
|
15013
|
+
telemetryPath,
|
|
15014
|
+
telemetryRecords: records.length,
|
|
15015
|
+
agentModels,
|
|
15016
|
+
opencodeConfigPaths,
|
|
15017
|
+
...opencodeConfig !== undefined ? { opencodeConfig } : {},
|
|
15018
|
+
...queueWait !== undefined ? { queueWait } : {},
|
|
15019
|
+
...rosterAudit !== undefined ? { rosterAudit } : {},
|
|
15020
|
+
...rosterRoleCount !== undefined ? { rosterRoleCount } : {},
|
|
15021
|
+
...rosterLoadError !== undefined ? { rosterLoadError } : {},
|
|
15022
|
+
...rosterMissing ? { rosterMissing } : {},
|
|
15023
|
+
...orchestratorAgentMissing ? { orchestratorAgentMissing } : {},
|
|
15024
|
+
...diagnostics !== undefined && diagnostics.length > 0 ? { diagnostics } : {},
|
|
15025
|
+
...opencodeConfigError !== undefined ? { opencodeConfigError } : {},
|
|
15026
|
+
...cacheEntries !== undefined ? { cacheEntries, cliVersion: deps.version } : {},
|
|
15027
|
+
...legacyLayout !== undefined && legacyLayout.length > 0 ? { legacyLayout } : {},
|
|
15028
|
+
...otelBackend !== undefined ? { otelBackend } : {},
|
|
15029
|
+
...gitignoreCoverage !== undefined ? { gitignore: gitignoreCoverage } : {}
|
|
15030
|
+
}),
|
|
15031
|
+
...inventoryNotes,
|
|
15032
|
+
...residencyNotes
|
|
15033
|
+
].join(`
|
|
15034
|
+
`)
|
|
14588
15035
|
};
|
|
14589
15036
|
}
|
|
14590
15037
|
if (command === "migrate") {
|
|
@@ -14768,29 +15215,29 @@ import {
|
|
|
14768
15215
|
writeFile as writeFile2
|
|
14769
15216
|
} from "node:fs/promises";
|
|
14770
15217
|
import { dirname as dirname5, join as join12, resolve as resolve7 } from "node:path";
|
|
14771
|
-
import { z as
|
|
15218
|
+
import { z as z22 } from "zod";
|
|
14772
15219
|
var CONSOLE_RUNTIME_SCHEMA_VERSION = 1;
|
|
14773
15220
|
var CONSOLE_RUNTIME_DIRECTORY = ".opencode/openteam-local/console";
|
|
14774
15221
|
var CONSOLE_RUNTIME_FILE = "runtime.json";
|
|
14775
15222
|
var CONSOLE_LAUNCH_LOCK_FILE = "launch.lock";
|
|
14776
15223
|
var CONSOLE_LOG_FILE = "console.log";
|
|
14777
|
-
var ConsoleRuntimeStateSchema =
|
|
14778
|
-
schemaVersion:
|
|
14779
|
-
pid:
|
|
14780
|
-
workspaceRoot:
|
|
14781
|
-
host:
|
|
14782
|
-
port:
|
|
14783
|
-
url:
|
|
14784
|
-
startedAt:
|
|
14785
|
-
launchId:
|
|
14786
|
-
logPath:
|
|
15224
|
+
var ConsoleRuntimeStateSchema = z22.object({
|
|
15225
|
+
schemaVersion: z22.literal(CONSOLE_RUNTIME_SCHEMA_VERSION),
|
|
15226
|
+
pid: z22.number().int().positive(),
|
|
15227
|
+
workspaceRoot: z22.string().min(1),
|
|
15228
|
+
host: z22.string().min(1),
|
|
15229
|
+
port: z22.number().int().min(1).max(65535),
|
|
15230
|
+
url: z22.url(),
|
|
15231
|
+
startedAt: z22.iso.datetime({ offset: true }),
|
|
15232
|
+
launchId: z22.uuid(),
|
|
15233
|
+
logPath: z22.string().min(1)
|
|
14787
15234
|
}).strict();
|
|
14788
|
-
var ConsoleLaunchLockSchema =
|
|
14789
|
-
schemaVersion:
|
|
14790
|
-
workspaceRoot:
|
|
14791
|
-
launchId:
|
|
14792
|
-
ownerPid:
|
|
14793
|
-
createdAt:
|
|
15235
|
+
var ConsoleLaunchLockSchema = z22.object({
|
|
15236
|
+
schemaVersion: z22.literal(CONSOLE_RUNTIME_SCHEMA_VERSION),
|
|
15237
|
+
workspaceRoot: z22.string().min(1),
|
|
15238
|
+
launchId: z22.uuid(),
|
|
15239
|
+
ownerPid: z22.number().int().positive(),
|
|
15240
|
+
createdAt: z22.iso.datetime({ offset: true })
|
|
14794
15241
|
}).strict();
|
|
14795
15242
|
|
|
14796
15243
|
class ConsoleRuntimeStateFileError extends Error {
|
|
@@ -15489,36 +15936,36 @@ function formatResponse(response) {
|
|
|
15489
15936
|
}
|
|
15490
15937
|
|
|
15491
15938
|
// src/plugin/reportRunSchema.ts
|
|
15492
|
-
import { z as
|
|
15939
|
+
import { z as z24 } from "zod";
|
|
15493
15940
|
|
|
15494
15941
|
// src/plugin/graphShadowIngress.ts
|
|
15495
|
-
import { z as
|
|
15942
|
+
import { z as z23 } from "zod";
|
|
15496
15943
|
var LEGACY_EXECUTION_TRACE_VERSION = 1;
|
|
15497
|
-
var LegacyExecutionStatusSchema =
|
|
15944
|
+
var LegacyExecutionStatusSchema = z23.enum([
|
|
15498
15945
|
"completed",
|
|
15499
15946
|
"failed",
|
|
15500
15947
|
"cancelled"
|
|
15501
15948
|
]);
|
|
15502
|
-
var LegacyReviewOutcomeSchema =
|
|
15949
|
+
var LegacyReviewOutcomeSchema = z23.enum([
|
|
15503
15950
|
"approved",
|
|
15504
15951
|
"rejected",
|
|
15505
15952
|
"inconclusive"
|
|
15506
15953
|
]);
|
|
15507
|
-
var LegacyTraceNodeV1Schema =
|
|
15954
|
+
var LegacyTraceNodeV1Schema = z23.object({
|
|
15508
15955
|
id: NodeIDSchema,
|
|
15509
15956
|
role: NodeRoleSchema,
|
|
15510
|
-
model:
|
|
15511
|
-
sessionRef:
|
|
15957
|
+
model: z23.string().min(1),
|
|
15958
|
+
sessionRef: z23.string().min(1).optional(),
|
|
15512
15959
|
errorClass: ErrorClassSchema.optional()
|
|
15513
15960
|
}).strict();
|
|
15514
|
-
var LegacyExecutionTraceV1Schema =
|
|
15515
|
-
version:
|
|
15961
|
+
var LegacyExecutionTraceV1Schema = z23.object({
|
|
15962
|
+
version: z23.literal(LEGACY_EXECUTION_TRACE_VERSION),
|
|
15516
15963
|
runID: NodeIDSchema,
|
|
15517
15964
|
status: LegacyExecutionStatusSchema,
|
|
15518
15965
|
outcome: LegacyReviewOutcomeSchema,
|
|
15519
|
-
fixes:
|
|
15520
|
-
nodes:
|
|
15521
|
-
parentSessionRef:
|
|
15966
|
+
fixes: z23.number().int().nonnegative(),
|
|
15967
|
+
nodes: z23.array(LegacyTraceNodeV1Schema).min(1),
|
|
15968
|
+
parentSessionRef: z23.string().min(1).optional()
|
|
15522
15969
|
}).strict();
|
|
15523
15970
|
function gateReason2(gate) {
|
|
15524
15971
|
if (gate === undefined || gate.mode === "off") {
|
|
@@ -15589,20 +16036,20 @@ function parseLegacyExecutionTrace(input) {
|
|
|
15589
16036
|
}
|
|
15590
16037
|
|
|
15591
16038
|
// src/plugin/reportRunSchema.ts
|
|
15592
|
-
var ReportRunNodeSchema =
|
|
16039
|
+
var ReportRunNodeSchema = z24.object({
|
|
15593
16040
|
id: NodeIDSchema,
|
|
15594
16041
|
role: NodeRoleSchema,
|
|
15595
|
-
model:
|
|
15596
|
-
ok:
|
|
15597
|
-
sessionRef:
|
|
16042
|
+
model: z24.string().min(1),
|
|
16043
|
+
ok: z24.boolean(),
|
|
16044
|
+
sessionRef: z24.string().min(1).optional(),
|
|
15598
16045
|
errorClass: ErrorClassSchema.optional()
|
|
15599
16046
|
}).strict();
|
|
15600
|
-
var ReportRunPayloadSchema =
|
|
16047
|
+
var ReportRunPayloadSchema = z24.object({
|
|
15601
16048
|
runID: NodeIDSchema,
|
|
15602
16049
|
status: LegacyExecutionStatusSchema,
|
|
15603
|
-
fixes:
|
|
15604
|
-
nodes:
|
|
15605
|
-
parentSessionRef:
|
|
16050
|
+
fixes: z24.number().int().nonnegative(),
|
|
16051
|
+
nodes: z24.array(ReportRunNodeSchema).min(1),
|
|
16052
|
+
parentSessionRef: z24.string().min(1).optional()
|
|
15606
16053
|
}).strict();
|
|
15607
16054
|
|
|
15608
16055
|
// src/orchestrator/graphShadow.ts
|
|
@@ -16706,6 +17153,309 @@ function hashPrompt(prompt) {
|
|
|
16706
17153
|
return `fnv1a32:${(hash >>> 0).toString(16).padStart(8, "0")}`;
|
|
16707
17154
|
}
|
|
16708
17155
|
|
|
17156
|
+
// src/plugin/modelResidency.ts
|
|
17157
|
+
import { z as z25 } from "zod";
|
|
17158
|
+
|
|
17159
|
+
// src/local/lemonadeRequestGuard.ts
|
|
17160
|
+
var inferencePaths = new Set([
|
|
17161
|
+
"/chat/completions",
|
|
17162
|
+
"/completions",
|
|
17163
|
+
"/embeddings",
|
|
17164
|
+
"/responses"
|
|
17165
|
+
]);
|
|
17166
|
+
function modelID(payload) {
|
|
17167
|
+
if (typeof payload !== "object" || payload === null || !("model" in payload) || typeof payload.model !== "string" || payload.model.length === 0 || payload.model !== payload.model.trim()) {
|
|
17168
|
+
throw new ModelResidencyError("request");
|
|
17169
|
+
}
|
|
17170
|
+
if (payload.model.endsWith(":latest"))
|
|
17171
|
+
throw new ModelResidencyError("identity");
|
|
17172
|
+
return payload.model;
|
|
17173
|
+
}
|
|
17174
|
+
function createLemonadeGuardedFetch(options) {
|
|
17175
|
+
const base = lemonadeBaseURL(options.baseURL);
|
|
17176
|
+
const upstream = options.fetch;
|
|
17177
|
+
const healthFetch = options.healthFetch ?? upstream;
|
|
17178
|
+
return Object.assign(async (input, init) => {
|
|
17179
|
+
const request = new Request(input, init);
|
|
17180
|
+
const url = new URL(request.url);
|
|
17181
|
+
if (url.username !== "" || url.password !== "" || url.search !== "" || url.hash !== "" || !request.url.startsWith(`${base}/`)) {
|
|
17182
|
+
throw new ModelResidencyError("destination");
|
|
17183
|
+
}
|
|
17184
|
+
const path4 = request.url.slice(base.length);
|
|
17185
|
+
const metadataOnly = request.method === "GET" && (path4 === "/health" || /^\/models(?:\/[^/]+)?$/.test(path4));
|
|
17186
|
+
if (!metadataOnly && (request.method !== "POST" || !inferencePaths.has(path4))) {
|
|
17187
|
+
throw new ModelResidencyError("request");
|
|
17188
|
+
}
|
|
17189
|
+
if (!metadataOnly) {
|
|
17190
|
+
await withResidencyDeadline(async (signal) => {
|
|
17191
|
+
signal.throwIfAborted();
|
|
17192
|
+
let payload;
|
|
17193
|
+
try {
|
|
17194
|
+
payload = await request.clone().json();
|
|
17195
|
+
} catch {
|
|
17196
|
+
signal.throwIfAborted();
|
|
17197
|
+
throw new ModelResidencyError("request");
|
|
17198
|
+
}
|
|
17199
|
+
signal.throwIfAborted();
|
|
17200
|
+
const model = modelID(payload);
|
|
17201
|
+
const modelIDs = typeof options.modelIDs === "function" ? await options.modelIDs() : options.modelIDs;
|
|
17202
|
+
signal.throwIfAborted();
|
|
17203
|
+
if (modelIDs !== undefined && !modelIDs.has(model)) {
|
|
17204
|
+
throw new ModelResidencyError("identity");
|
|
17205
|
+
}
|
|
17206
|
+
const residency = await readLemonadeResidency(base, healthFetch, {
|
|
17207
|
+
...options,
|
|
17208
|
+
signal,
|
|
17209
|
+
headers: request.headers
|
|
17210
|
+
});
|
|
17211
|
+
signal.throwIfAborted();
|
|
17212
|
+
const entry = residency.get(model);
|
|
17213
|
+
if (entry?.loaded !== true) {
|
|
17214
|
+
throw new ModelResidencyError(entry?.loaded === undefined && entry !== undefined ? "unknown" : "inactive");
|
|
17215
|
+
}
|
|
17216
|
+
}, { ...options, signal: request.signal });
|
|
17217
|
+
}
|
|
17218
|
+
if (request.signal.aborted)
|
|
17219
|
+
throw new ModelResidencyError("cancelled");
|
|
17220
|
+
const {
|
|
17221
|
+
body: _body,
|
|
17222
|
+
headers: _headers,
|
|
17223
|
+
method: _method,
|
|
17224
|
+
signal: _signal,
|
|
17225
|
+
redirect: _redirect,
|
|
17226
|
+
...transportOptions
|
|
17227
|
+
} = init ?? {};
|
|
17228
|
+
return upstream(request, { ...transportOptions, redirect: "error" });
|
|
17229
|
+
}, {
|
|
17230
|
+
preconnect: (...args) => upstream.preconnect?.(...args)
|
|
17231
|
+
});
|
|
17232
|
+
}
|
|
17233
|
+
|
|
17234
|
+
// src/plugin/modelResidency.ts
|
|
17235
|
+
function isFetch(value) {
|
|
17236
|
+
return typeof value === "function";
|
|
17237
|
+
}
|
|
17238
|
+
function origin(value) {
|
|
17239
|
+
return typeof value === "string" && URL.canParse(value) ? new URL(value).origin : undefined;
|
|
17240
|
+
}
|
|
17241
|
+
var TEMPLATE_REFERENCE = /\$\{[^}]+\}/;
|
|
17242
|
+
function resolveTemplateReferences(value, readEnv) {
|
|
17243
|
+
let unresolved = false;
|
|
17244
|
+
const resolved = value.replace(/\$\{([^}]+)\}/g, (match, key) => {
|
|
17245
|
+
const resolvedValue = readEnv(key);
|
|
17246
|
+
if (resolvedValue === undefined) {
|
|
17247
|
+
unresolved = true;
|
|
17248
|
+
return match;
|
|
17249
|
+
}
|
|
17250
|
+
return resolvedValue;
|
|
17251
|
+
});
|
|
17252
|
+
return unresolved ? undefined : resolved;
|
|
17253
|
+
}
|
|
17254
|
+
function endpointBinding(value, readEnv) {
|
|
17255
|
+
if (!TEMPLATE_REFERENCE.test(value))
|
|
17256
|
+
return { ambiguous: false, origin: origin(value) };
|
|
17257
|
+
const resolved = resolveTemplateReferences(value, readEnv);
|
|
17258
|
+
return resolved === undefined ? { ambiguous: true } : { ambiguous: false, origin: origin(resolved) };
|
|
17259
|
+
}
|
|
17260
|
+
function optionBaseURL(value) {
|
|
17261
|
+
return typeof value === "string" && value !== "" ? value : undefined;
|
|
17262
|
+
}
|
|
17263
|
+
function providerBase(provider, model) {
|
|
17264
|
+
return optionBaseURL(provider.options?.baseURL) ?? model?.provider?.api ?? provider.api;
|
|
17265
|
+
}
|
|
17266
|
+
function providerRoutes(provider) {
|
|
17267
|
+
const models = Object.values(provider.models ?? {});
|
|
17268
|
+
return (models.length === 0 ? [undefined] : models).map((model) => ({
|
|
17269
|
+
baseURL: providerBase(provider, model),
|
|
17270
|
+
npm: model?.provider?.npm ?? provider.npm
|
|
17271
|
+
}));
|
|
17272
|
+
}
|
|
17273
|
+
function wireID(key, model) {
|
|
17274
|
+
const id = model?.id ?? key;
|
|
17275
|
+
if (id.length === 0 || id !== id.trim())
|
|
17276
|
+
throw new ModelResidencyError("identity");
|
|
17277
|
+
return id;
|
|
17278
|
+
}
|
|
17279
|
+
function nativeEligibleID(id) {
|
|
17280
|
+
return id === "openai" || id === "anthropic" || id.startsWith("opencode");
|
|
17281
|
+
}
|
|
17282
|
+
function configuredRuntime(config, providerID) {
|
|
17283
|
+
const runtimes = config.local.runtimes.filter((runtime2) => runtime2.defaultModel.providerID === providerID);
|
|
17284
|
+
const runtime = runtimes[0];
|
|
17285
|
+
if (runtimes.length !== 1 || runtime === undefined || !runtime.enabled) {
|
|
17286
|
+
throw new ModelResidencyError("destination");
|
|
17287
|
+
}
|
|
17288
|
+
return runtime;
|
|
17289
|
+
}
|
|
17290
|
+
function createModelResidencyGuard(config, options) {
|
|
17291
|
+
const guarded = new Map;
|
|
17292
|
+
const blocked = new Set;
|
|
17293
|
+
let hostConfig;
|
|
17294
|
+
const readEnv = options.readEnv ?? ((name) => process.env[name]);
|
|
17295
|
+
const lemonadeRuntimes = () => config.local.runtimes.filter((runtime) => localRuntimeKind(runtime) === "lemonade");
|
|
17296
|
+
const protects = (providerID, baseURL) => lemonadeRuntimes().some((runtime) => {
|
|
17297
|
+
if (runtime.defaultModel.providerID === providerID)
|
|
17298
|
+
return true;
|
|
17299
|
+
if (baseURL === undefined)
|
|
17300
|
+
return false;
|
|
17301
|
+
const binding = endpointBinding(baseURL, readEnv);
|
|
17302
|
+
if (binding.ambiguous)
|
|
17303
|
+
return true;
|
|
17304
|
+
return binding.origin !== undefined && binding.origin === origin(runtime.baseURL ?? LEMONADE_DEFAULT_BASE_URL);
|
|
17305
|
+
});
|
|
17306
|
+
const resolvedWireID = (model, declaredID) => {
|
|
17307
|
+
const id = options.resolveApiModelID === undefined ? declaredID : options.resolveApiModelID(model);
|
|
17308
|
+
if (id === undefined)
|
|
17309
|
+
throw new ModelResidencyError("identity");
|
|
17310
|
+
return wireID(id, undefined);
|
|
17311
|
+
};
|
|
17312
|
+
const configHook = async (host) => {
|
|
17313
|
+
hostConfig = host;
|
|
17314
|
+
const previousGuards = new Map(guarded);
|
|
17315
|
+
guarded.clear();
|
|
17316
|
+
blocked.clear();
|
|
17317
|
+
for (const [providerID, provider] of Object.entries(host.provider ?? {})) {
|
|
17318
|
+
const routes = providerRoutes(provider);
|
|
17319
|
+
if (!routes.some((route) => protects(providerID, route.baseURL)))
|
|
17320
|
+
continue;
|
|
17321
|
+
const previous = previousGuards.get(providerID);
|
|
17322
|
+
const configuredFetch = provider.options?.fetch;
|
|
17323
|
+
const originalFetch = previous !== undefined && configuredFetch === previous.fetch ? previous.originalFetch : configuredFetch ?? options.fetch;
|
|
17324
|
+
blocked.add(providerID);
|
|
17325
|
+
const wasDisabled = host.disabled_providers?.includes(providerID) ?? false;
|
|
17326
|
+
host.disabled_providers = [
|
|
17327
|
+
...new Set([...host.disabled_providers ?? [], providerID])
|
|
17328
|
+
];
|
|
17329
|
+
const reject = Object.assign(async () => {
|
|
17330
|
+
throw new ModelResidencyError("transport");
|
|
17331
|
+
}, { preconnect: () => {} });
|
|
17332
|
+
provider.options = { ...provider.options, fetch: reject };
|
|
17333
|
+
try {
|
|
17334
|
+
const runtime = configuredRuntime(config, providerID);
|
|
17335
|
+
const baseURL = lemonadeBaseURL(runtime.baseURL ?? LEMONADE_DEFAULT_BASE_URL);
|
|
17336
|
+
if (localRuntimeKind(runtime) !== "lemonade" || routes.some((route) => route.baseURL === undefined || lemonadeBaseURL(route.baseURL) !== baseURL))
|
|
17337
|
+
throw new ModelResidencyError("destination");
|
|
17338
|
+
if (routes.some((route) => route.npm !== "@ai-sdk/openai-compatible") || nativeEligibleID(providerID) || !isFetch(originalFetch))
|
|
17339
|
+
throw new ModelResidencyError("transport");
|
|
17340
|
+
const modelKeys = new Map;
|
|
17341
|
+
for (const [key, model] of Object.entries(provider.models ?? {})) {
|
|
17342
|
+
if (model.options?.fetch !== undefined || model.options?.baseURL !== undefined && (typeof model.options.baseURL !== "string" || lemonadeBaseURL(model.options.baseURL) !== baseURL))
|
|
17343
|
+
throw new ModelResidencyError("transport");
|
|
17344
|
+
modelKeys.set(key, wireID(key, model));
|
|
17345
|
+
}
|
|
17346
|
+
if (!modelKeys.has(runtime.defaultModel.modelID))
|
|
17347
|
+
modelKeys.set(runtime.defaultModel.modelID, undefined);
|
|
17348
|
+
const modelIDs = () => {
|
|
17349
|
+
const ids = new Set;
|
|
17350
|
+
for (const [modelID2, declaredID] of modelKeys) {
|
|
17351
|
+
const id = options.resolveApiModelID === undefined ? declaredID : options.resolveApiModelID({ providerID, modelID: modelID2 });
|
|
17352
|
+
if (id !== undefined)
|
|
17353
|
+
ids.add(wireID(id, undefined));
|
|
17354
|
+
}
|
|
17355
|
+
return ids;
|
|
17356
|
+
};
|
|
17357
|
+
const fetch = createLemonadeGuardedFetch({
|
|
17358
|
+
...options,
|
|
17359
|
+
baseURL,
|
|
17360
|
+
modelIDs: async () => {
|
|
17361
|
+
await options.modelInventoryReady?.();
|
|
17362
|
+
return modelIDs();
|
|
17363
|
+
},
|
|
17364
|
+
fetch: originalFetch,
|
|
17365
|
+
healthFetch: options.fetch
|
|
17366
|
+
});
|
|
17367
|
+
provider.options.fetch = fetch;
|
|
17368
|
+
guarded.set(providerID, {
|
|
17369
|
+
baseURL,
|
|
17370
|
+
fetch,
|
|
17371
|
+
originalFetch,
|
|
17372
|
+
modelIDs,
|
|
17373
|
+
modelKeys
|
|
17374
|
+
});
|
|
17375
|
+
blocked.delete(providerID);
|
|
17376
|
+
if (!wasDisabled) {
|
|
17377
|
+
host.disabled_providers = host.disabled_providers.filter((id) => id !== providerID);
|
|
17378
|
+
}
|
|
17379
|
+
} catch (error) {
|
|
17380
|
+
if (!(error instanceof ModelResidencyError))
|
|
17381
|
+
throw error;
|
|
17382
|
+
(options.warn ?? console.warn)(modelResidencyMessages.providerDisabled(providerID));
|
|
17383
|
+
}
|
|
17384
|
+
}
|
|
17385
|
+
};
|
|
17386
|
+
const beforeInference = async (input) => {
|
|
17387
|
+
const base = optionBaseURL(input.provider.options.baseURL) ?? input.model.api.url;
|
|
17388
|
+
if (!protects(input.model.providerID, base))
|
|
17389
|
+
return;
|
|
17390
|
+
const provider = guarded.get(input.model.providerID);
|
|
17391
|
+
if (provider === undefined || blocked.has(input.model.providerID) || input.provider.options.fetch !== provider.fetch || input.model.api.npm !== "@ai-sdk/openai-compatible" || nativeEligibleID(input.model.providerID))
|
|
17392
|
+
throw new ModelResidencyError("transport");
|
|
17393
|
+
if (lemonadeBaseURL(base) !== provider.baseURL) {
|
|
17394
|
+
throw new ModelResidencyError("destination");
|
|
17395
|
+
}
|
|
17396
|
+
const id = resolvedWireID({ providerID: input.model.providerID, modelID: input.model.id }, provider.modelKeys.get(input.model.id));
|
|
17397
|
+
if (id !== input.model.api.id)
|
|
17398
|
+
throw new ModelResidencyError("identity");
|
|
17399
|
+
if (!provider.modelKeys.has(input.model.id))
|
|
17400
|
+
provider.modelKeys.set(input.model.id, undefined);
|
|
17401
|
+
};
|
|
17402
|
+
const localTarget = (model) => {
|
|
17403
|
+
const runtime = configuredRuntime(config, model.providerID);
|
|
17404
|
+
if (hostConfig?.disabled_providers?.includes(model.providerID)) {
|
|
17405
|
+
throw new ModelResidencyError("transport");
|
|
17406
|
+
}
|
|
17407
|
+
if (runtime.baseURL === undefined)
|
|
17408
|
+
throw new ModelResidencyError("destination");
|
|
17409
|
+
const provider = hostConfig?.provider?.[model.providerID];
|
|
17410
|
+
const entry = Object.hasOwn(provider?.models ?? {}, model.modelID) ? provider?.models?.[model.modelID] : undefined;
|
|
17411
|
+
const configuredURL = provider === undefined ? undefined : providerBase(provider, entry);
|
|
17412
|
+
if (configuredURL !== undefined && new URL(configuredURL).href.replace(/\/$/, "") !== new URL(runtime.baseURL).href.replace(/\/$/, "")) {
|
|
17413
|
+
throw new ModelResidencyError("destination");
|
|
17414
|
+
}
|
|
17415
|
+
const modelID2 = resolvedWireID(model, entry === undefined && localRuntimeKind(runtime) === "lemonade" ? undefined : wireID(model.modelID, entry));
|
|
17416
|
+
let fetch = options.fetch;
|
|
17417
|
+
if (localRuntimeKind(runtime) === "lemonade") {
|
|
17418
|
+
const installed = guarded.get(model.providerID);
|
|
17419
|
+
if (installed === undefined || blocked.has(model.providerID)) {
|
|
17420
|
+
throw new ModelResidencyError("transport");
|
|
17421
|
+
}
|
|
17422
|
+
if (installed.baseURL !== lemonadeBaseURL(runtime.baseURL)) {
|
|
17423
|
+
throw new ModelResidencyError("destination");
|
|
17424
|
+
}
|
|
17425
|
+
if (!installed.modelKeys.has(model.modelID))
|
|
17426
|
+
installed.modelKeys.set(model.modelID, undefined);
|
|
17427
|
+
if (!installed.modelIDs().has(modelID2))
|
|
17428
|
+
throw new ModelResidencyError("identity");
|
|
17429
|
+
fetch = installed.fetch;
|
|
17430
|
+
}
|
|
17431
|
+
const configuredHeaders = z25.record(z25.string(), z25.string()).safeParse(provider?.options?.headers ?? {});
|
|
17432
|
+
if (!configuredHeaders.success)
|
|
17433
|
+
throw new ModelResidencyError("configuration");
|
|
17434
|
+
const headers = new Headers(configuredHeaders.data);
|
|
17435
|
+
if (typeof provider?.options?.apiKey === "string" && !headers.has("authorization")) {
|
|
17436
|
+
headers.set("authorization", `Bearer ${provider.options.apiKey}`);
|
|
17437
|
+
}
|
|
17438
|
+
for (const [name, value] of Object.entries(entry?.headers ?? {}))
|
|
17439
|
+
headers.set(name, value);
|
|
17440
|
+
const upstream = fetch;
|
|
17441
|
+
return {
|
|
17442
|
+
baseURL: runtime.baseURL,
|
|
17443
|
+
modelID: modelID2,
|
|
17444
|
+
fetch: [...headers].length === 0 ? fetch : Object.assign(async (input, init) => {
|
|
17445
|
+
const request = new Request(input, init);
|
|
17446
|
+
for (const [name, value] of headers) {
|
|
17447
|
+
if (!request.headers.has(name))
|
|
17448
|
+
request.headers.set(name, value);
|
|
17449
|
+
}
|
|
17450
|
+
return upstream(request);
|
|
17451
|
+
}, {
|
|
17452
|
+
preconnect: (...args) => upstream.preconnect?.(...args)
|
|
17453
|
+
})
|
|
17454
|
+
};
|
|
17455
|
+
};
|
|
17456
|
+
return { config: configHook, beforeInference, localTarget };
|
|
17457
|
+
}
|
|
17458
|
+
|
|
16709
17459
|
// src/plugin/hooks.ts
|
|
16710
17460
|
var codeSignals = [
|
|
16711
17461
|
"```",
|
|
@@ -16849,7 +17599,10 @@ function createChatMessageHook(config, getAvailable, options = {}) {
|
|
|
16849
17599
|
};
|
|
16850
17600
|
}
|
|
16851
17601
|
function createHooks(config, getAvailable, options = {}) {
|
|
17602
|
+
const residency = options.modelResidency ?? createModelResidencyGuard(config, { fetch: globalThis.fetch });
|
|
16852
17603
|
return {
|
|
17604
|
+
config: residency.config,
|
|
17605
|
+
"chat.params": residency.beforeInference,
|
|
16853
17606
|
"chat.message": createChatMessageHook(config, getAvailable, options)
|
|
16854
17607
|
};
|
|
16855
17608
|
}
|
|
@@ -16903,62 +17656,62 @@ ${lines.join(`
|
|
|
16903
17656
|
}
|
|
16904
17657
|
|
|
16905
17658
|
// src/memory/types.ts
|
|
16906
|
-
import { z as
|
|
17659
|
+
import { z as z26 } from "zod";
|
|
16907
17660
|
var SHARED_OWNER_KEY = "*";
|
|
16908
|
-
var OwnerKeySchema =
|
|
16909
|
-
var MemoryKindSchema =
|
|
16910
|
-
var MemoryBaseSchema =
|
|
16911
|
-
id:
|
|
17661
|
+
var OwnerKeySchema = z26.string().min(1);
|
|
17662
|
+
var MemoryKindSchema = z26.enum(["fact", "preference", "entity"]);
|
|
17663
|
+
var MemoryBaseSchema = z26.object({
|
|
17664
|
+
id: z26.string().min(1),
|
|
16912
17665
|
ownerKey: OwnerKeySchema,
|
|
16913
|
-
confidence:
|
|
16914
|
-
validFrom:
|
|
16915
|
-
validUntil:
|
|
16916
|
-
createdAt:
|
|
16917
|
-
invalidatedAt:
|
|
16918
|
-
sourceHash:
|
|
16919
|
-
supersededBy:
|
|
17666
|
+
confidence: z26.number().min(0).max(1),
|
|
17667
|
+
validFrom: z26.number().finite(),
|
|
17668
|
+
validUntil: z26.number().finite().nullable().default(null),
|
|
17669
|
+
createdAt: z26.number().finite(),
|
|
17670
|
+
invalidatedAt: z26.number().finite().nullable().default(null),
|
|
17671
|
+
sourceHash: z26.string().min(1),
|
|
17672
|
+
supersededBy: z26.string().min(1).nullable().default(null)
|
|
16920
17673
|
}).strict();
|
|
16921
17674
|
var FactSchema = MemoryBaseSchema.extend({
|
|
16922
|
-
kind:
|
|
16923
|
-
subject:
|
|
16924
|
-
predicate:
|
|
16925
|
-
object:
|
|
16926
|
-
category:
|
|
17675
|
+
kind: z26.literal("fact"),
|
|
17676
|
+
subject: z26.string().min(1),
|
|
17677
|
+
predicate: z26.string().min(1),
|
|
17678
|
+
object: z26.string().min(1),
|
|
17679
|
+
category: z26.string().min(1).nullable().default(null)
|
|
16927
17680
|
});
|
|
16928
17681
|
var PreferenceSchema = MemoryBaseSchema.extend({
|
|
16929
|
-
kind:
|
|
16930
|
-
category:
|
|
16931
|
-
preference:
|
|
16932
|
-
context:
|
|
16933
|
-
lastAccessedAt:
|
|
16934
|
-
accessCount:
|
|
17682
|
+
kind: z26.literal("preference"),
|
|
17683
|
+
category: z26.string().min(1),
|
|
17684
|
+
preference: z26.string().min(1),
|
|
17685
|
+
context: z26.string().min(1).nullable().default(null),
|
|
17686
|
+
lastAccessedAt: z26.number().finite().nullable().default(null),
|
|
17687
|
+
accessCount: z26.number().int().min(0).default(0)
|
|
16935
17688
|
});
|
|
16936
17689
|
var EntitySchema = MemoryBaseSchema.extend({
|
|
16937
|
-
kind:
|
|
16938
|
-
canonicalName:
|
|
16939
|
-
type:
|
|
16940
|
-
aliases:
|
|
17690
|
+
kind: z26.literal("entity"),
|
|
17691
|
+
canonicalName: z26.string().min(1),
|
|
17692
|
+
type: z26.string().min(1),
|
|
17693
|
+
aliases: z26.array(z26.string().min(1)).default([])
|
|
16941
17694
|
});
|
|
16942
17695
|
var RelationSchema = MemoryBaseSchema.extend({
|
|
16943
|
-
kind:
|
|
16944
|
-
from:
|
|
16945
|
-
to:
|
|
16946
|
-
predicate:
|
|
16947
|
-
annotation:
|
|
17696
|
+
kind: z26.literal("relation"),
|
|
17697
|
+
from: z26.string().min(1),
|
|
17698
|
+
to: z26.string().min(1),
|
|
17699
|
+
predicate: z26.string().min(1),
|
|
17700
|
+
annotation: z26.string().min(1).nullable().default(null)
|
|
16948
17701
|
});
|
|
16949
|
-
var MemoryRecordSchema =
|
|
17702
|
+
var MemoryRecordSchema = z26.discriminatedUnion("kind", [
|
|
16950
17703
|
FactSchema,
|
|
16951
17704
|
PreferenceSchema,
|
|
16952
17705
|
EntitySchema,
|
|
16953
17706
|
RelationSchema
|
|
16954
17707
|
]);
|
|
16955
|
-
var RecallQuerySchema =
|
|
17708
|
+
var RecallQuerySchema = z26.object({
|
|
16956
17709
|
ownerKey: OwnerKeySchema,
|
|
16957
|
-
kinds:
|
|
16958
|
-
asOf:
|
|
16959
|
-
limit:
|
|
16960
|
-
minSimilarity:
|
|
16961
|
-
includeShared:
|
|
17710
|
+
kinds: z26.array(MemoryKindSchema).default(["fact", "preference", "entity"]),
|
|
17711
|
+
asOf: z26.number().finite().nullable().default(null),
|
|
17712
|
+
limit: z26.number().int().positive().default(8),
|
|
17713
|
+
minSimilarity: z26.number().min(0).max(1).default(0.2),
|
|
17714
|
+
includeShared: z26.boolean().default(true)
|
|
16962
17715
|
}).strict();
|
|
16963
17716
|
|
|
16964
17717
|
// src/memory/rank.ts
|
|
@@ -17529,42 +18282,42 @@ function buildMemoryInjector(deps, policy) {
|
|
|
17529
18282
|
|
|
17530
18283
|
// src/plugin/memoryTool.ts
|
|
17531
18284
|
import { tool as tool4 } from "@opencode-ai/plugin";
|
|
17532
|
-
import { z as
|
|
18285
|
+
import { z as z28 } from "zod";
|
|
17533
18286
|
|
|
17534
18287
|
// src/memory/extract.ts
|
|
17535
|
-
import { z as
|
|
18288
|
+
import { z as z27 } from "zod";
|
|
17536
18289
|
var REDACTED = "[redacted]";
|
|
17537
|
-
var RawFactSchema =
|
|
17538
|
-
subject:
|
|
17539
|
-
predicate:
|
|
17540
|
-
object:
|
|
17541
|
-
category:
|
|
17542
|
-
confidence:
|
|
18290
|
+
var RawFactSchema = z27.object({
|
|
18291
|
+
subject: z27.string().min(1),
|
|
18292
|
+
predicate: z27.string().min(1),
|
|
18293
|
+
object: z27.string().min(1),
|
|
18294
|
+
category: z27.string().min(1).nullable().optional(),
|
|
18295
|
+
confidence: z27.number().min(0).max(1).optional()
|
|
17543
18296
|
});
|
|
17544
|
-
var RawPreferenceSchema =
|
|
17545
|
-
category:
|
|
17546
|
-
preference:
|
|
17547
|
-
context:
|
|
17548
|
-
confidence:
|
|
18297
|
+
var RawPreferenceSchema = z27.object({
|
|
18298
|
+
category: z27.string().min(1),
|
|
18299
|
+
preference: z27.string().min(1),
|
|
18300
|
+
context: z27.string().min(1).nullable().optional(),
|
|
18301
|
+
confidence: z27.number().min(0).max(1).optional()
|
|
17549
18302
|
});
|
|
17550
|
-
var RawEntitySchema =
|
|
17551
|
-
canonicalName:
|
|
17552
|
-
type:
|
|
17553
|
-
aliases:
|
|
17554
|
-
confidence:
|
|
18303
|
+
var RawEntitySchema = z27.object({
|
|
18304
|
+
canonicalName: z27.string().min(1),
|
|
18305
|
+
type: z27.string().min(1),
|
|
18306
|
+
aliases: z27.array(z27.string().min(1)).optional(),
|
|
18307
|
+
confidence: z27.number().min(0).max(1).optional()
|
|
17555
18308
|
});
|
|
17556
|
-
var RawRelationSchema =
|
|
17557
|
-
from:
|
|
17558
|
-
to:
|
|
17559
|
-
predicate:
|
|
17560
|
-
annotation:
|
|
17561
|
-
confidence:
|
|
18309
|
+
var RawRelationSchema = z27.object({
|
|
18310
|
+
from: z27.string().min(1),
|
|
18311
|
+
to: z27.string().min(1),
|
|
18312
|
+
predicate: z27.string().min(1),
|
|
18313
|
+
annotation: z27.string().min(1).nullable().optional(),
|
|
18314
|
+
confidence: z27.number().min(0).max(1).optional()
|
|
17562
18315
|
}).strict();
|
|
17563
|
-
var RawExtractionSchema =
|
|
17564
|
-
facts:
|
|
17565
|
-
preferences:
|
|
17566
|
-
entities:
|
|
17567
|
-
relations:
|
|
18316
|
+
var RawExtractionSchema = z27.object({
|
|
18317
|
+
facts: z27.array(RawFactSchema).default([]),
|
|
18318
|
+
preferences: z27.array(RawPreferenceSchema).default([]),
|
|
18319
|
+
entities: z27.array(RawEntitySchema).default([]),
|
|
18320
|
+
relations: z27.array(RawRelationSchema).default([])
|
|
17568
18321
|
});
|
|
17569
18322
|
var DEFAULT_CONFIDENCE = 0.6;
|
|
17570
18323
|
var SYSTEM_PROMPT = [
|
|
@@ -17818,13 +18571,13 @@ var memoryToolMessages = {
|
|
|
17818
18571
|
|
|
17819
18572
|
// src/plugin/memoryTool.ts
|
|
17820
18573
|
var SCRIBE_ROLE_ID = "scribe";
|
|
17821
|
-
var MemoryMessageSchema =
|
|
17822
|
-
role:
|
|
17823
|
-
content:
|
|
18574
|
+
var MemoryMessageSchema = z28.object({
|
|
18575
|
+
role: z28.enum(["system", "user", "assistant"]).describe(memoryToolMessages.messageRoleDescription),
|
|
18576
|
+
content: z28.string().min(1).describe(memoryToolMessages.messageContentDescription)
|
|
17824
18577
|
}).strict();
|
|
17825
|
-
var MemoryWritePayloadSchema =
|
|
17826
|
-
messages:
|
|
17827
|
-
roleID:
|
|
18578
|
+
var MemoryWritePayloadSchema = z28.object({
|
|
18579
|
+
messages: z28.array(MemoryMessageSchema).min(1).describe(memoryToolMessages.messagesDescription),
|
|
18580
|
+
roleID: z28.string().min(1).default(SCRIBE_ROLE_ID).describe(memoryToolMessages.roleIDDescription)
|
|
17828
18581
|
}).strict();
|
|
17829
18582
|
function createMemoryTool(deps) {
|
|
17830
18583
|
return tool4({
|
|
@@ -17836,7 +18589,7 @@ function createMemoryTool(deps) {
|
|
|
17836
18589
|
})).describe(memoryToolMessages.messagesDescription),
|
|
17837
18590
|
roleID: tool4.schema.string().optional().describe(memoryToolMessages.roleIDDescription)
|
|
17838
18591
|
},
|
|
17839
|
-
async execute(args) {
|
|
18592
|
+
async execute(args, toolContext) {
|
|
17840
18593
|
const parsed = MemoryWritePayloadSchema.safeParse(args);
|
|
17841
18594
|
if (!parsed.success) {
|
|
17842
18595
|
return memoryToolMessages.validationError(parsed.error.message);
|
|
@@ -17857,33 +18610,83 @@ function createMemoryTool(deps) {
|
|
|
17857
18610
|
if (executionMode2 === "frontier") {
|
|
17858
18611
|
return memoryToolMessages.frontierDomainRefusal;
|
|
17859
18612
|
}
|
|
17860
|
-
if (!await deps.localRuntimeReachable()) {
|
|
17861
|
-
return memoryToolMessages.localRuntimeUnavailable;
|
|
17862
|
-
}
|
|
17863
|
-
const runtime = deps.config.local.runtimes.find((rt) => rt.enabled && typeof rt.baseURL === "string" && rt.baseURL.length > 0);
|
|
17864
|
-
if (runtime?.baseURL === undefined) {
|
|
17865
|
-
return memoryToolMessages.localRuntimeBaseURLMissing;
|
|
17866
|
-
}
|
|
17867
|
-
const modelID = semantic.extraction.model?.modelID ?? runtime.defaultModel.modelID;
|
|
17868
|
-
const transcript = messages.map((m) => `${m.role}: ${m.content}`).join(`
|
|
17869
|
-
`);
|
|
17870
|
-
const sourceHash = sha256Hex(transcript);
|
|
17871
|
-
const now = deps.now();
|
|
17872
|
-
const context = {
|
|
17873
|
-
ownerKey: semantic.scope === "user" ? "user" : "project",
|
|
17874
|
-
now,
|
|
17875
|
-
sourceHash,
|
|
17876
|
-
storeContent: semantic.storeContent,
|
|
17877
|
-
idPrefix: `${sourceHash.slice(0, 12)}:${now}`
|
|
17878
|
-
};
|
|
17879
18613
|
let records;
|
|
17880
18614
|
try {
|
|
18615
|
+
const signal = toolContext.abort;
|
|
18616
|
+
const throwIfAborted = () => {
|
|
18617
|
+
if (signal?.aborted)
|
|
18618
|
+
throw new ModelResidencyError("cancelled");
|
|
18619
|
+
};
|
|
18620
|
+
throwIfAborted();
|
|
18621
|
+
const configuredModel = semantic.extraction.model;
|
|
18622
|
+
let runtime;
|
|
18623
|
+
if (configuredModel != null) {
|
|
18624
|
+
const matches = deps.config.local.runtimes.filter((candidate) => candidate.defaultModel.providerID === configuredModel.providerID);
|
|
18625
|
+
runtime = matches[0];
|
|
18626
|
+
if (matches.length !== 1 || runtime === undefined || !runtime.enabled) {
|
|
18627
|
+
return modelResidencyMessages.extractionRuntimeUnavailable;
|
|
18628
|
+
}
|
|
18629
|
+
} else {
|
|
18630
|
+
runtime = deps.config.local.runtimes.find((candidate) => candidate.enabled && typeof candidate.baseURL === "string" && candidate.baseURL.length > 0);
|
|
18631
|
+
}
|
|
18632
|
+
if (runtime?.baseURL === undefined || runtime.baseURL.length === 0) {
|
|
18633
|
+
return memoryToolMessages.localRuntimeBaseURLMissing;
|
|
18634
|
+
}
|
|
18635
|
+
const baseURL = runtime.baseURL;
|
|
18636
|
+
const model = configuredModel ?? runtime.defaultModel;
|
|
18637
|
+
const selectedRuntime = runtime;
|
|
18638
|
+
const deadline = {
|
|
18639
|
+
...deps.residencyOptions,
|
|
18640
|
+
...signal === undefined ? {} : { signal }
|
|
18641
|
+
};
|
|
18642
|
+
const reachable = localRuntimeKind(runtime) === "lemonade" ? await withResidencyDeadline((signal2) => deps.localRuntimeReachable(selectedRuntime, signal2), deadline) : await deps.localRuntimeReachable(runtime);
|
|
18643
|
+
throwIfAborted();
|
|
18644
|
+
if (!reachable)
|
|
18645
|
+
return memoryToolMessages.localRuntimeUnavailable;
|
|
18646
|
+
const resolveTarget = deps.resolveExtractionTarget;
|
|
18647
|
+
const target = resolveTarget ? await withResidencyDeadline(async () => resolveTarget(model), deadline) : {
|
|
18648
|
+
baseURL,
|
|
18649
|
+
modelID: model.modelID,
|
|
18650
|
+
fetch: localRuntimeKind(runtime) === "lemonade" ? createLemonadeGuardedFetch({
|
|
18651
|
+
baseURL,
|
|
18652
|
+
fetch: deps.fetch,
|
|
18653
|
+
modelIDs: new Set([model.modelID]),
|
|
18654
|
+
...deps.residencyOptions
|
|
18655
|
+
}) : deps.fetch
|
|
18656
|
+
};
|
|
18657
|
+
throwIfAborted();
|
|
18658
|
+
if (target === undefined || target.baseURL !== baseURL) {
|
|
18659
|
+
throw new ModelResidencyError("destination");
|
|
18660
|
+
}
|
|
18661
|
+
const fetch = signal === undefined ? target.fetch : Object.assign(async (input, init) => {
|
|
18662
|
+
throwIfAborted();
|
|
18663
|
+
const response = await target.fetch(input, {
|
|
18664
|
+
...init,
|
|
18665
|
+
signal
|
|
18666
|
+
});
|
|
18667
|
+
throwIfAborted();
|
|
18668
|
+
return response;
|
|
18669
|
+
}, {
|
|
18670
|
+
preconnect: (...args2) => target.fetch.preconnect?.(...args2)
|
|
18671
|
+
});
|
|
18672
|
+
const transcript = messages.map((m) => `${m.role}: ${m.content}`).join(`
|
|
18673
|
+
`);
|
|
18674
|
+
const sourceHash = sha256Hex(transcript);
|
|
18675
|
+
const now = deps.now();
|
|
18676
|
+
const context = {
|
|
18677
|
+
ownerKey: semantic.scope === "user" ? "user" : "project",
|
|
18678
|
+
now,
|
|
18679
|
+
sourceHash,
|
|
18680
|
+
storeContent: semantic.storeContent,
|
|
18681
|
+
idPrefix: `${sourceHash.slice(0, 12)}:${now}`
|
|
18682
|
+
};
|
|
17881
18683
|
records = await extractMemory({
|
|
17882
|
-
baseURL:
|
|
17883
|
-
modelID,
|
|
18684
|
+
baseURL: target.baseURL,
|
|
18685
|
+
modelID: target.modelID,
|
|
17884
18686
|
messages,
|
|
17885
18687
|
context
|
|
17886
|
-
}, { fetch
|
|
18688
|
+
}, { fetch, ...deps.warn ? { warn: deps.warn } : {} });
|
|
18689
|
+
throwIfAborted();
|
|
17887
18690
|
} catch (error) {
|
|
17888
18691
|
const reason = error instanceof Error ? error.message : String(error);
|
|
17889
18692
|
return memoryToolMessages.extractionFailure(reason);
|
|
@@ -17949,10 +18752,10 @@ function createOrchestratedModelOwnership() {
|
|
|
17949
18752
|
|
|
17950
18753
|
// src/plugin/orchestrateTool.ts
|
|
17951
18754
|
import { tool as tool5 } from "@opencode-ai/plugin";
|
|
17952
|
-
import { z as
|
|
18755
|
+
import { z as z30 } from "zod";
|
|
17953
18756
|
|
|
17954
18757
|
// src/orchestrator/coordinator.ts
|
|
17955
|
-
import { z as
|
|
18758
|
+
import { z as z29 } from "zod";
|
|
17956
18759
|
|
|
17957
18760
|
// src/orchestrator/nodeIteration.ts
|
|
17958
18761
|
var DEFAULT_MAX_RETRIES = 2;
|
|
@@ -18162,12 +18965,15 @@ async function applyReportDurabilityGate(results, probe) {
|
|
|
18162
18965
|
}
|
|
18163
18966
|
|
|
18164
18967
|
// src/orchestrator/runtimeSelection.ts
|
|
18165
|
-
function
|
|
18968
|
+
function configuredRuntime2(runtimeId, config) {
|
|
18166
18969
|
return config.local.runtimes.find((runtime) => runtime.id === runtimeId);
|
|
18167
18970
|
}
|
|
18168
18971
|
function runtimeIdOfModel(model, config) {
|
|
18169
18972
|
return config.local.runtimes.find((runtime) => sameModel(runtime.defaultModel, model))?.id;
|
|
18170
18973
|
}
|
|
18974
|
+
function enabledRuntimeForProvider(providerID, config) {
|
|
18975
|
+
return config.local.runtimes.find((runtime) => runtime.enabled && runtime.defaultModel.providerID === providerID)?.id;
|
|
18976
|
+
}
|
|
18171
18977
|
function roleLocalModel(role, runtimeId, fallback, runtime) {
|
|
18172
18978
|
const pinned = role.localModels?.[runtimeId];
|
|
18173
18979
|
if (pinned !== undefined) {
|
|
@@ -18182,7 +18988,7 @@ function runtimeClassModel(modelClass, runtime) {
|
|
|
18182
18988
|
}
|
|
18183
18989
|
return modelClass === "thinking" ? runtime.thinkingModel : runtime.coderModel;
|
|
18184
18990
|
}
|
|
18185
|
-
function selectDispatchRuntime(role, decision2, reachable, config) {
|
|
18991
|
+
function selectDispatchRuntime(role, decision2, reachable, config, availableModels2) {
|
|
18186
18992
|
if (decision2.routeKind !== "local") {
|
|
18187
18993
|
return { runtimeId: undefined, decision: decision2 };
|
|
18188
18994
|
}
|
|
@@ -18193,7 +18999,7 @@ function selectDispatchRuntime(role, decision2, reachable, config) {
|
|
|
18193
18999
|
if (!reachable.has(runtimeId)) {
|
|
18194
19000
|
continue;
|
|
18195
19001
|
}
|
|
18196
|
-
const runtime =
|
|
19002
|
+
const runtime = configuredRuntime2(runtimeId, config);
|
|
18197
19003
|
if (runtime?.defaultModel.providerID === decision2.selected.providerID) {
|
|
18198
19004
|
return { runtimeId, decision: decision2 };
|
|
18199
19005
|
}
|
|
@@ -18203,15 +19009,17 @@ function selectDispatchRuntime(role, decision2, reachable, config) {
|
|
|
18203
19009
|
if (exactRuntimeId !== undefined) {
|
|
18204
19010
|
return { runtimeId: exactRuntimeId, decision: decision2 };
|
|
18205
19011
|
}
|
|
18206
|
-
|
|
18207
|
-
|
|
19012
|
+
return {
|
|
19013
|
+
runtimeId: enabledRuntimeForProvider(decision2.selected.providerID, config),
|
|
19014
|
+
decision: decision2
|
|
19015
|
+
};
|
|
18208
19016
|
}
|
|
18209
19017
|
if (listed !== undefined && listed.length > 0 && reachable !== undefined) {
|
|
18210
19018
|
for (const runtimeId of listed) {
|
|
18211
19019
|
if (!reachable.has(runtimeId)) {
|
|
18212
19020
|
continue;
|
|
18213
19021
|
}
|
|
18214
|
-
const runtime =
|
|
19022
|
+
const runtime = configuredRuntime2(runtimeId, config);
|
|
18215
19023
|
if (runtime === undefined) {
|
|
18216
19024
|
continue;
|
|
18217
19025
|
}
|
|
@@ -18224,7 +19032,7 @@ function selectDispatchRuntime(role, decision2, reachable, config) {
|
|
|
18224
19032
|
}
|
|
18225
19033
|
const resolvedRuntimeId = runtimeIdOfModel(decision2.selected, config);
|
|
18226
19034
|
if (resolvedRuntimeId !== undefined) {
|
|
18227
|
-
const pinned = roleLocalModel(role, resolvedRuntimeId, decision2.selected,
|
|
19035
|
+
const pinned = roleLocalModel(role, resolvedRuntimeId, decision2.selected, configuredRuntime2(resolvedRuntimeId, config));
|
|
18228
19036
|
if (pinned !== decision2.selected) {
|
|
18229
19037
|
return {
|
|
18230
19038
|
runtimeId: resolvedRuntimeId,
|
|
@@ -18232,8 +19040,9 @@ function selectDispatchRuntime(role, decision2, reachable, config) {
|
|
|
18232
19040
|
};
|
|
18233
19041
|
}
|
|
18234
19042
|
}
|
|
19043
|
+
const knownAlias = localModelAliases(decision2.selected.providerID, availableModels2).has(decision2.selected.modelID);
|
|
18235
19044
|
return {
|
|
18236
|
-
runtimeId: resolvedRuntimeId,
|
|
19045
|
+
runtimeId: resolvedRuntimeId ?? (knownAlias ? enabledRuntimeForProvider(decision2.selected.providerID, config) : undefined),
|
|
18237
19046
|
decision: decision2
|
|
18238
19047
|
};
|
|
18239
19048
|
}
|
|
@@ -18420,7 +19229,7 @@ function buildRecord(input, decision2, subsession, deps, decisionID, batchID) {
|
|
|
18420
19229
|
}
|
|
18421
19230
|
return record;
|
|
18422
19231
|
}
|
|
18423
|
-
var TelemetryFailureClassSchema =
|
|
19232
|
+
var TelemetryFailureClassSchema = z29.enum([
|
|
18424
19233
|
"create-rejected",
|
|
18425
19234
|
"create-no-id",
|
|
18426
19235
|
"prompt-rejected",
|
|
@@ -18679,7 +19488,7 @@ async function runRoleTaskWithCorrelation(input, deps, correlation, batch, route
|
|
|
18679
19488
|
if (routed.routeKind === "blocked") {
|
|
18680
19489
|
throw new Error(coordinatorRoutingBlocked(input.roleID, routed.blockReason));
|
|
18681
19490
|
}
|
|
18682
|
-
const selection = selectDispatchRuntime(role, routed, batch.set, input.config);
|
|
19491
|
+
const selection = selectDispatchRuntime(role, routed, batch.set, input.config, input.availableModels);
|
|
18683
19492
|
const decision2 = selection.decision;
|
|
18684
19493
|
const composed = composeSubsessionPrompt({
|
|
18685
19494
|
prompt: input.prompt,
|
|
@@ -18761,8 +19570,9 @@ async function runRoleTaskWithCorrelation(input, deps, correlation, batch, route
|
|
|
18761
19570
|
if (runtimeId !== undefined && deps.runtimeLimiter !== undefined) {
|
|
18762
19571
|
const limiter = deps.runtimeLimiter;
|
|
18763
19572
|
const priority = priorityForRole(role);
|
|
18764
|
-
const dispatchRuntime =
|
|
18765
|
-
const
|
|
19573
|
+
const dispatchRuntime = configuredRuntime2(runtimeId, input.config) ?? { id: runtimeId };
|
|
19574
|
+
const aliases = localModelAliases(decision2.selected.providerID, input.availableModels);
|
|
19575
|
+
const poolKey = slotPoolKey(withReportedModelSlots(dispatchRuntime, deps.reportedModelSlots?.(runtimeId), aliases), aliases.get(decision2.selected.modelID) ?? decision2.selected.modelID);
|
|
18766
19576
|
release = limiter.tryAcquire(poolKey, priority);
|
|
18767
19577
|
let waitedMs = 0;
|
|
18768
19578
|
if (release === undefined) {
|
|
@@ -19236,7 +20046,7 @@ async function runRoleTasks(inputs, deps, options = {}) {
|
|
|
19236
20046
|
var _pluginWarnedRoles = new Set;
|
|
19237
20047
|
var EMPTY_ROLE_ID_SET = new Set;
|
|
19238
20048
|
var SAFE_ROLE_ID = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;
|
|
19239
|
-
var RoleIDSchema =
|
|
20049
|
+
var RoleIDSchema = z30.string().min(1).superRefine((roleID, ctx) => {
|
|
19240
20050
|
if (!SAFE_ROLE_ID.test(roleID)) {
|
|
19241
20051
|
ctx.addIssue({
|
|
19242
20052
|
code: "custom",
|
|
@@ -19244,16 +20054,16 @@ var RoleIDSchema = z28.string().min(1).superRefine((roleID, ctx) => {
|
|
|
19244
20054
|
});
|
|
19245
20055
|
}
|
|
19246
20056
|
});
|
|
19247
|
-
var RoleAssignmentSchema =
|
|
20057
|
+
var RoleAssignmentSchema = z30.object({
|
|
19248
20058
|
roleID: RoleIDSchema.describe("Role identifier from the roster"),
|
|
19249
|
-
prompt:
|
|
19250
|
-
title:
|
|
19251
|
-
dependsOn:
|
|
20059
|
+
prompt: z30.string().min(1).describe("Work prompt for this role"),
|
|
20060
|
+
title: z30.string().min(1).optional().describe("Human-readable title"),
|
|
20061
|
+
dependsOn: z30.array(RoleIDSchema).optional().describe("Role IDs this assignment depends on (DAG edges)")
|
|
19252
20062
|
}).strict();
|
|
19253
|
-
var OrchestratePayloadSchema =
|
|
19254
|
-
assignments:
|
|
19255
|
-
parentSessionID:
|
|
19256
|
-
directory:
|
|
20063
|
+
var OrchestratePayloadSchema = z30.object({
|
|
20064
|
+
assignments: z30.array(RoleAssignmentSchema).min(1).describe("Role assignments to distribute"),
|
|
20065
|
+
parentSessionID: z30.string().min(1).optional().describe(PARENT_SESSION_DESCRIPTION),
|
|
20066
|
+
directory: z30.string().min(1).optional().describe("Working directory override")
|
|
19257
20067
|
}).strict();
|
|
19258
20068
|
function validateAssignmentDependencies(assignments) {
|
|
19259
20069
|
const ids = new Set;
|
|
@@ -19989,7 +20799,7 @@ ${advisory}`;
|
|
|
19989
20799
|
|
|
19990
20800
|
// src/plugin/registerCastTool.ts
|
|
19991
20801
|
import { tool as tool6 } from "@opencode-ai/plugin";
|
|
19992
|
-
import { z as
|
|
20802
|
+
import { z as z31 } from "zod";
|
|
19993
20803
|
|
|
19994
20804
|
// src/messages/rosterSummary.ts
|
|
19995
20805
|
var ROSTER_SUMMARY_HEADING = "Registered team model policies";
|
|
@@ -20218,13 +21028,13 @@ async function persistPreparedTeam(storage, files) {
|
|
|
20218
21028
|
}
|
|
20219
21029
|
|
|
20220
21030
|
// src/plugin/registerCastTool.ts
|
|
20221
|
-
var CastEntrySchema =
|
|
20222
|
-
roleID:
|
|
20223
|
-
agentName:
|
|
21031
|
+
var CastEntrySchema = z31.object({
|
|
21032
|
+
roleID: z31.string().min(1).describe("Stable role identifier, e.g. scribe or guardian"),
|
|
21033
|
+
agentName: z31.string().min(1).describe("Themed character name assigned to the role")
|
|
20224
21034
|
}).strict();
|
|
20225
|
-
var RegisterCastPayloadSchema =
|
|
20226
|
-
universe:
|
|
20227
|
-
entries:
|
|
21035
|
+
var RegisterCastPayloadSchema = z31.object({
|
|
21036
|
+
universe: z31.string().min(1).describe("Casting universe for this roster"),
|
|
21037
|
+
entries: z31.array(CastEntrySchema).min(1).describe("Role-to-name mappings")
|
|
20228
21038
|
}).strict();
|
|
20229
21039
|
function offendingFields(error) {
|
|
20230
21040
|
const fields = error.issues.flatMap((issue) => {
|
|
@@ -20343,6 +21153,307 @@ function createRegisterCastTool(deps) {
|
|
|
20343
21153
|
});
|
|
20344
21154
|
}
|
|
20345
21155
|
|
|
21156
|
+
// src/plugin/reloadTool.ts
|
|
21157
|
+
import { resolve as resolve9 } from "node:path";
|
|
21158
|
+
import { tool as tool7 } from "@opencode-ai/plugin/tool";
|
|
21159
|
+
var WAIT_MS = 30000;
|
|
21160
|
+
var SDK_TIMEOUT_MS = 5000;
|
|
21161
|
+
var POLL_MS2 = 1000;
|
|
21162
|
+
var schema = tool7.schema.object({
|
|
21163
|
+
action: tool7.schema.enum(["request", "cancel"]).describe(reloadMessages.action),
|
|
21164
|
+
confirmed: tool7.schema.boolean().describe(reloadMessages.confirmed)
|
|
21165
|
+
}).strict();
|
|
21166
|
+
function sdkData(value) {
|
|
21167
|
+
if (typeof value !== "object" || value === null)
|
|
21168
|
+
return;
|
|
21169
|
+
try {
|
|
21170
|
+
const prototype = Object.getPrototypeOf(value);
|
|
21171
|
+
if (prototype !== Object.prototype && prototype !== null)
|
|
21172
|
+
return;
|
|
21173
|
+
const error = Object.getOwnPropertyDescriptor(value, "error");
|
|
21174
|
+
const data = Object.getOwnPropertyDescriptor(value, "data");
|
|
21175
|
+
if (error !== undefined && (!("value" in error) || error.value !== undefined))
|
|
21176
|
+
return;
|
|
21177
|
+
return data !== undefined && "value" in data ? data.value : undefined;
|
|
21178
|
+
} catch {
|
|
21179
|
+
return;
|
|
21180
|
+
}
|
|
21181
|
+
}
|
|
21182
|
+
function createReloadController(deps) {
|
|
21183
|
+
const scheduler = deps.scheduler ?? {
|
|
21184
|
+
now: () => Date.now(),
|
|
21185
|
+
schedule: (run, ms) => {
|
|
21186
|
+
const timer = setTimeout(run, ms);
|
|
21187
|
+
timer.unref();
|
|
21188
|
+
return () => clearTimeout(timer);
|
|
21189
|
+
}
|
|
21190
|
+
};
|
|
21191
|
+
const directory = resolve9(deps.directory);
|
|
21192
|
+
let pending;
|
|
21193
|
+
let authorizing;
|
|
21194
|
+
let closed = false;
|
|
21195
|
+
function current(request) {
|
|
21196
|
+
return pending === request && !request.abort.signal.aborted;
|
|
21197
|
+
}
|
|
21198
|
+
function finish(request, code) {
|
|
21199
|
+
if (!current(request))
|
|
21200
|
+
return;
|
|
21201
|
+
pending = undefined;
|
|
21202
|
+
request.stopDeadline();
|
|
21203
|
+
request.stopPoll?.();
|
|
21204
|
+
request.unlinkCaller();
|
|
21205
|
+
request.abort.abort();
|
|
21206
|
+
deps.notify(code);
|
|
21207
|
+
}
|
|
21208
|
+
function revokeAuthorization() {
|
|
21209
|
+
authorizing?.abort.abort();
|
|
21210
|
+
authorizing = undefined;
|
|
21211
|
+
}
|
|
21212
|
+
function cancel() {
|
|
21213
|
+
revokeAuthorization();
|
|
21214
|
+
if (pending !== undefined)
|
|
21215
|
+
finish(pending, pending.disposing ? "reload-unconfirmed" : "reload-cancelled");
|
|
21216
|
+
}
|
|
21217
|
+
async function requestPermission(context, authorization) {
|
|
21218
|
+
let finishInterruption;
|
|
21219
|
+
const interrupted = new Promise((done) => {
|
|
21220
|
+
finishInterruption = done;
|
|
21221
|
+
});
|
|
21222
|
+
const onAbort = () => finishInterruption("cancelled");
|
|
21223
|
+
const stopTimer = scheduler.schedule(() => finishInterruption("timeout"), Math.max(0, authorization.deadline - scheduler.now()));
|
|
21224
|
+
context.abort.addEventListener("abort", onAbort, { once: true });
|
|
21225
|
+
authorization.abort.signal.addEventListener("abort", onAbort, {
|
|
21226
|
+
once: true
|
|
21227
|
+
});
|
|
21228
|
+
try {
|
|
21229
|
+
return await Promise.race([
|
|
21230
|
+
context.ask({
|
|
21231
|
+
permission: "openteam-reload",
|
|
21232
|
+
patterns: [directory],
|
|
21233
|
+
always: [directory],
|
|
21234
|
+
metadata: { directory }
|
|
21235
|
+
}).then(() => "approved"),
|
|
21236
|
+
interrupted
|
|
21237
|
+
]);
|
|
21238
|
+
} finally {
|
|
21239
|
+
stopTimer();
|
|
21240
|
+
context.abort.removeEventListener("abort", onAbort);
|
|
21241
|
+
authorization.abort.signal.removeEventListener("abort", onAbort);
|
|
21242
|
+
}
|
|
21243
|
+
}
|
|
21244
|
+
function bounded(request, run) {
|
|
21245
|
+
return new Promise((done) => {
|
|
21246
|
+
const operation = new AbortController;
|
|
21247
|
+
let settled = false;
|
|
21248
|
+
const settle = (outcome) => {
|
|
21249
|
+
if (settled)
|
|
21250
|
+
return;
|
|
21251
|
+
settled = true;
|
|
21252
|
+
stopTimer();
|
|
21253
|
+
request.abort.signal.removeEventListener("abort", onAbort);
|
|
21254
|
+
if (outcome.kind !== "settled")
|
|
21255
|
+
operation.abort();
|
|
21256
|
+
done(outcome);
|
|
21257
|
+
};
|
|
21258
|
+
const onAbort = () => settle({ kind: "cancelled" });
|
|
21259
|
+
const stopTimer = scheduler.schedule(() => settle({ kind: "timeout" }), Math.max(0, Math.min(SDK_TIMEOUT_MS, request.deadline - scheduler.now())));
|
|
21260
|
+
request.abort.signal.addEventListener("abort", onAbort, { once: true });
|
|
21261
|
+
try {
|
|
21262
|
+
run(operation.signal).then((value) => settle({ kind: "settled", value }), () => settle({ kind: "failed" }));
|
|
21263
|
+
} catch {
|
|
21264
|
+
settle({ kind: "failed" });
|
|
21265
|
+
}
|
|
21266
|
+
});
|
|
21267
|
+
}
|
|
21268
|
+
function poll(request) {
|
|
21269
|
+
if (!current(request) || request.stopPoll !== undefined)
|
|
21270
|
+
return;
|
|
21271
|
+
request.stopPoll = scheduler.schedule(() => {
|
|
21272
|
+
request.stopPoll = undefined;
|
|
21273
|
+
probe(request);
|
|
21274
|
+
}, POLL_MS2);
|
|
21275
|
+
}
|
|
21276
|
+
async function probe(request) {
|
|
21277
|
+
if (!current(request) || !request.callerIdle || request.probing || request.disposing)
|
|
21278
|
+
return;
|
|
21279
|
+
if (scheduler.now() >= request.deadline) {
|
|
21280
|
+
finish(request, "reload-timeout");
|
|
21281
|
+
return;
|
|
21282
|
+
}
|
|
21283
|
+
request.stopPoll?.();
|
|
21284
|
+
request.stopPoll = undefined;
|
|
21285
|
+
request.probing = true;
|
|
21286
|
+
const revision = request.revision;
|
|
21287
|
+
try {
|
|
21288
|
+
for (let check = 0;check < 2; check++) {
|
|
21289
|
+
const outcome2 = await bounded(request, (signal) => deps.client.session.status({ query: { directory }, signal }));
|
|
21290
|
+
if (!current(request))
|
|
21291
|
+
return;
|
|
21292
|
+
if (outcome2.kind !== "settled") {
|
|
21293
|
+
finish(request, "reload-status-failed");
|
|
21294
|
+
return;
|
|
21295
|
+
}
|
|
21296
|
+
const snapshot = parseSessionStatusMap(sdkData(outcome2.value));
|
|
21297
|
+
if (snapshot === undefined) {
|
|
21298
|
+
finish(request, "reload-status-failed");
|
|
21299
|
+
return;
|
|
21300
|
+
}
|
|
21301
|
+
if (revision !== request.revision || !request.callerIdle) {
|
|
21302
|
+
poll(request);
|
|
21303
|
+
return;
|
|
21304
|
+
}
|
|
21305
|
+
if (Object.values(snapshot).some((status) => status.type !== "idle")) {
|
|
21306
|
+
if (Object.hasOwn(snapshot, request.sessionID) && snapshot[request.sessionID]?.type !== "idle")
|
|
21307
|
+
request.callerIdle = false;
|
|
21308
|
+
if (!request.waitingReported) {
|
|
21309
|
+
request.waitingReported = true;
|
|
21310
|
+
deps.notify("reload-waiting");
|
|
21311
|
+
}
|
|
21312
|
+
poll(request);
|
|
21313
|
+
return;
|
|
21314
|
+
}
|
|
21315
|
+
}
|
|
21316
|
+
if (scheduler.now() >= request.deadline) {
|
|
21317
|
+
finish(request, "reload-timeout");
|
|
21318
|
+
return;
|
|
21319
|
+
}
|
|
21320
|
+
request.disposing = true;
|
|
21321
|
+
closed = true;
|
|
21322
|
+
const outcome = await bounded(request, (signal) => deps.client.instance.dispose({ query: { directory }, signal }));
|
|
21323
|
+
if (!current(request))
|
|
21324
|
+
return;
|
|
21325
|
+
finish(request, outcome.kind === "timeout" ? "reload-unconfirmed" : outcome.kind === "settled" && sdkData(outcome.value) === true ? "reload-accepted" : "reload-dispose-failed");
|
|
21326
|
+
} finally {
|
|
21327
|
+
request.probing = false;
|
|
21328
|
+
if (current(request) && request.callerIdle && !request.disposing && revision !== request.revision)
|
|
21329
|
+
probe(request);
|
|
21330
|
+
}
|
|
21331
|
+
}
|
|
21332
|
+
const definition = {
|
|
21333
|
+
description: reloadMessages.description,
|
|
21334
|
+
args: schema.shape,
|
|
21335
|
+
async execute(args, context) {
|
|
21336
|
+
const parsed = schema.safeParse(args);
|
|
21337
|
+
if (!parsed.success)
|
|
21338
|
+
return reloadMessages.invalid;
|
|
21339
|
+
if (context.agent !== "openteam" || resolve9(context.directory) !== directory || context.sessionID.trim().length === 0)
|
|
21340
|
+
return reloadMessages.denied;
|
|
21341
|
+
if (parsed.data.action === "cancel") {
|
|
21342
|
+
if ((pending?.sessionID ?? authorizing?.sessionID) !== context.sessionID)
|
|
21343
|
+
return reloadMessages.none;
|
|
21344
|
+
const message = pending?.disposing ? reloadMessages["reload-unconfirmed"] : reloadMessages["reload-cancelled"];
|
|
21345
|
+
cancel();
|
|
21346
|
+
return message;
|
|
21347
|
+
}
|
|
21348
|
+
if (!parsed.data.confirmed) {
|
|
21349
|
+
const inFlight = pending?.sessionID === context.sessionID && pending.disposing;
|
|
21350
|
+
if ((pending?.sessionID ?? authorizing?.sessionID) === context.sessionID)
|
|
21351
|
+
cancel();
|
|
21352
|
+
return inFlight ? reloadMessages["reload-unconfirmed"] : reloadMessages.declined;
|
|
21353
|
+
}
|
|
21354
|
+
if (context.abort.aborted)
|
|
21355
|
+
return reloadMessages["reload-cancelled"];
|
|
21356
|
+
if (closed)
|
|
21357
|
+
return reloadMessages.closed;
|
|
21358
|
+
if (authorizing !== undefined)
|
|
21359
|
+
return authorizing.sessionID === context.sessionID ? reloadMessages.authorizing : reloadMessages.other;
|
|
21360
|
+
if (pending !== undefined) {
|
|
21361
|
+
if (pending.sessionID !== context.sessionID)
|
|
21362
|
+
return reloadMessages.other;
|
|
21363
|
+
pending.toolDone = false;
|
|
21364
|
+
pending.callerIdle = false;
|
|
21365
|
+
pending.revision++;
|
|
21366
|
+
return reloadMessages["reload-queued"];
|
|
21367
|
+
}
|
|
21368
|
+
const authorization = {
|
|
21369
|
+
sessionID: context.sessionID,
|
|
21370
|
+
deadline: scheduler.now() + WAIT_MS,
|
|
21371
|
+
abort: new AbortController
|
|
21372
|
+
};
|
|
21373
|
+
authorizing = authorization;
|
|
21374
|
+
try {
|
|
21375
|
+
const permission = await requestPermission(context, authorization);
|
|
21376
|
+
if (closed)
|
|
21377
|
+
return reloadMessages.closed;
|
|
21378
|
+
if (authorizing !== authorization || context.abort.aborted || permission === "cancelled")
|
|
21379
|
+
return reloadMessages["reload-cancelled"];
|
|
21380
|
+
if (permission === "timeout" || scheduler.now() >= authorization.deadline) {
|
|
21381
|
+
deps.notify("reload-timeout");
|
|
21382
|
+
return reloadMessages["reload-timeout"];
|
|
21383
|
+
}
|
|
21384
|
+
const onAbort = () => {
|
|
21385
|
+
if (pending === request)
|
|
21386
|
+
cancel();
|
|
21387
|
+
};
|
|
21388
|
+
const request = {
|
|
21389
|
+
sessionID: context.sessionID,
|
|
21390
|
+
deadline: authorization.deadline,
|
|
21391
|
+
abort: new AbortController,
|
|
21392
|
+
unlinkCaller: () => context.abort.removeEventListener("abort", onAbort),
|
|
21393
|
+
stopDeadline: () => {},
|
|
21394
|
+
stopPoll: undefined,
|
|
21395
|
+
toolDone: false,
|
|
21396
|
+
callerIdle: false,
|
|
21397
|
+
probing: false,
|
|
21398
|
+
disposing: false,
|
|
21399
|
+
waitingReported: false,
|
|
21400
|
+
revision: 0
|
|
21401
|
+
};
|
|
21402
|
+
pending = request;
|
|
21403
|
+
context.abort.addEventListener("abort", onAbort, { once: true });
|
|
21404
|
+
request.stopDeadline = scheduler.schedule(() => finish(request, request.disposing ? "reload-unconfirmed" : "reload-timeout"), request.deadline - scheduler.now());
|
|
21405
|
+
deps.notify("reload-queued");
|
|
21406
|
+
return reloadMessages["reload-queued"];
|
|
21407
|
+
} finally {
|
|
21408
|
+
if (authorizing === authorization)
|
|
21409
|
+
authorizing = undefined;
|
|
21410
|
+
}
|
|
21411
|
+
}
|
|
21412
|
+
};
|
|
21413
|
+
return {
|
|
21414
|
+
tool: definition,
|
|
21415
|
+
toolCompleted(sessionID) {
|
|
21416
|
+
if (pending?.sessionID !== sessionID)
|
|
21417
|
+
return;
|
|
21418
|
+
pending.unlinkCaller();
|
|
21419
|
+
pending.toolDone = true;
|
|
21420
|
+
pending.callerIdle = false;
|
|
21421
|
+
pending.revision++;
|
|
21422
|
+
},
|
|
21423
|
+
userTurn(_sessionID) {
|
|
21424
|
+
cancel();
|
|
21425
|
+
},
|
|
21426
|
+
event(event) {
|
|
21427
|
+
const sessionID = pending?.sessionID ?? authorizing?.sessionID;
|
|
21428
|
+
if (sessionID === undefined)
|
|
21429
|
+
return;
|
|
21430
|
+
if (event.type === "session.error" && (event.properties.sessionID === undefined || event.properties.sessionID === sessionID) || event.type === "session.deleted" && event.properties.info.id === sessionID) {
|
|
21431
|
+
cancel();
|
|
21432
|
+
return;
|
|
21433
|
+
}
|
|
21434
|
+
if (event.type === "session.created" || event.type === "session.status" && event.properties.status.type !== "idle")
|
|
21435
|
+
revokeAuthorization();
|
|
21436
|
+
const request = pending;
|
|
21437
|
+
if (request === undefined)
|
|
21438
|
+
return;
|
|
21439
|
+
if (event.type === "session.created" || event.type === "session.status") {
|
|
21440
|
+
request.revision++;
|
|
21441
|
+
if (event.type === "session.status" && event.properties.sessionID === request.sessionID && event.properties.status.type !== "idle")
|
|
21442
|
+
request.callerIdle = false;
|
|
21443
|
+
}
|
|
21444
|
+
if (event.type === "session.idle" || event.type === "session.status" && event.properties.status.type === "idle") {
|
|
21445
|
+
if (event.properties.sessionID === request.sessionID && request.toolDone)
|
|
21446
|
+
request.callerIdle = true;
|
|
21447
|
+
probe(request);
|
|
21448
|
+
}
|
|
21449
|
+
},
|
|
21450
|
+
dispose() {
|
|
21451
|
+
closed = true;
|
|
21452
|
+
cancel();
|
|
21453
|
+
}
|
|
21454
|
+
};
|
|
21455
|
+
}
|
|
21456
|
+
|
|
20346
21457
|
// src/plugin/sessionTracker.ts
|
|
20347
21458
|
function createSessionTracker() {
|
|
20348
21459
|
const knownSessions = new Set;
|
|
@@ -20542,7 +21653,7 @@ async function buildMemoryRuntimeFromConfig(config, deps, options = {}) {
|
|
|
20542
21653
|
if (runtime?.baseURL === undefined) {
|
|
20543
21654
|
return;
|
|
20544
21655
|
}
|
|
20545
|
-
const
|
|
21656
|
+
const modelID2 = semantic.embeddings.model?.modelID ?? runtime.defaultModel.modelID;
|
|
20546
21657
|
const openDatabase = deps.openDatabase ?? createBunSqliteDatabase;
|
|
20547
21658
|
const makeEmbedder = deps.createEmbedder ?? createLocalEmbedder;
|
|
20548
21659
|
const fetchImpl = deps.fetch ?? globalThis.fetch;
|
|
@@ -20555,8 +21666,8 @@ async function buildMemoryRuntimeFromConfig(config, deps, options = {}) {
|
|
|
20555
21666
|
if (rebuildResult.rejectedLines > 0) {
|
|
20556
21667
|
warn(`[openteam] memory log rejected ${rebuildResult.rejectedLines} line(s); semantic memory may be incomplete.`);
|
|
20557
21668
|
}
|
|
20558
|
-
const embedder = makeEmbedder({ baseURL: runtime.baseURL, modelID }, { fetch: fetchImpl });
|
|
20559
|
-
await ensureMemoryEmbeddings({ index, embedder, model:
|
|
21669
|
+
const embedder = makeEmbedder({ baseURL: runtime.baseURL, modelID: modelID2 }, { fetch: fetchImpl });
|
|
21670
|
+
await ensureMemoryEmbeddings({ index, embedder, model: modelID2, warn });
|
|
20560
21671
|
return {
|
|
20561
21672
|
index,
|
|
20562
21673
|
embedder,
|
|
@@ -20580,22 +21691,22 @@ import {
|
|
|
20580
21691
|
statSync,
|
|
20581
21692
|
unlinkSync as unlinkSync2
|
|
20582
21693
|
} from "node:fs";
|
|
20583
|
-
import { join as join15, resolve as
|
|
21694
|
+
import { join as join15, resolve as resolve11 } from "node:path";
|
|
20584
21695
|
import { ZodError } from "zod";
|
|
20585
21696
|
|
|
20586
21697
|
// src/storage/lifecycle/codec.ts
|
|
20587
|
-
import { z as
|
|
21698
|
+
import { z as z32 } from "zod";
|
|
20588
21699
|
var LIFECYCLE_CODEC_VERSION = 1;
|
|
20589
21700
|
var LIFECYCLE_GENESIS_DIGEST = sha256Hex("openteam/lifecycle-journal/genesis/v1");
|
|
20590
21701
|
var NUL5 = "\x00";
|
|
20591
21702
|
var NEWLINE2 = `
|
|
20592
21703
|
`;
|
|
20593
|
-
var frameSchema =
|
|
20594
|
-
v:
|
|
20595
|
-
seq:
|
|
20596
|
-
prev:
|
|
20597
|
-
sum:
|
|
20598
|
-
event:
|
|
21704
|
+
var frameSchema = z32.object({
|
|
21705
|
+
v: z32.literal(LIFECYCLE_CODEC_VERSION),
|
|
21706
|
+
seq: z32.number().int().nonnegative(),
|
|
21707
|
+
prev: z32.string().min(1),
|
|
21708
|
+
sum: z32.string().min(1),
|
|
21709
|
+
event: z32.unknown()
|
|
20599
21710
|
}).strict();
|
|
20600
21711
|
function canonical2(value) {
|
|
20601
21712
|
if (Array.isArray(value)) {
|
|
@@ -20699,7 +21810,7 @@ import {
|
|
|
20699
21810
|
unlinkSync,
|
|
20700
21811
|
writeSync as writeSync2
|
|
20701
21812
|
} from "node:fs";
|
|
20702
|
-
import { basename as basename3, dirname as dirname7, join as join14, relative as relative3, resolve as
|
|
21813
|
+
import { basename as basename3, dirname as dirname7, join as join14, relative as relative3, resolve as resolve10 } from "node:path";
|
|
20703
21814
|
var SAFE_RUN_ID = /^[A-Za-z0-9](?:[A-Za-z0-9._-]{0,126}[A-Za-z0-9])?$/u;
|
|
20704
21815
|
|
|
20705
21816
|
class LifecycleFsError extends Error {
|
|
@@ -20723,7 +21834,7 @@ function validateRunID(runID) {
|
|
|
20723
21834
|
}
|
|
20724
21835
|
function resolvedLifecycleRoot(root) {
|
|
20725
21836
|
try {
|
|
20726
|
-
const absolute =
|
|
21837
|
+
const absolute = resolve10(root);
|
|
20727
21838
|
mkdirSync2(absolute, { recursive: true });
|
|
20728
21839
|
const rootStat = lstatSync2(absolute);
|
|
20729
21840
|
if (!rootStat.isDirectory() || rootStat.isSymbolicLink()) {
|
|
@@ -20766,7 +21877,7 @@ function assertExistingSafeRun(root, runID) {
|
|
|
20766
21877
|
throw new LifecycleFsError("unavailable");
|
|
20767
21878
|
}
|
|
20768
21879
|
const child = relative3(root, real);
|
|
20769
|
-
if (child === "" || child.startsWith("..") ||
|
|
21880
|
+
if (child === "" || child.startsWith("..") || resolve10(root, child) !== real || dirname7(real) !== root) {
|
|
20770
21881
|
throw new LifecycleFsError("corrupt");
|
|
20771
21882
|
}
|
|
20772
21883
|
return real;
|
|
@@ -20935,8 +22046,8 @@ function readRun(runDir, runID) {
|
|
|
20935
22046
|
if (metadataText === undefined || eventsText === undefined) {
|
|
20936
22047
|
throw new LifecycleFsError("corrupt");
|
|
20937
22048
|
}
|
|
20938
|
-
const
|
|
20939
|
-
if (
|
|
22049
|
+
const metadata2 = parseJson(metadataText, parseLifecycleRunMetadata);
|
|
22050
|
+
if (metadata2.runID !== runID) {
|
|
20940
22051
|
throw new LifecycleFsError("corrupt");
|
|
20941
22052
|
}
|
|
20942
22053
|
let decoded;
|
|
@@ -20951,10 +22062,10 @@ function readRun(runDir, runID) {
|
|
|
20951
22062
|
}
|
|
20952
22063
|
}
|
|
20953
22064
|
const first = decoded.events[0];
|
|
20954
|
-
if (first === undefined || first.type !== "run.started" || first.source !==
|
|
22065
|
+
if (first === undefined || first.type !== "run.started" || first.source !== metadata2.source || first.executionAuthority !== metadata2.executionAuthority || first.root.operationID !== metadata2.root.operationID || first.root.taskID !== metadata2.root.taskID) {
|
|
20955
22066
|
throw new LifecycleFsError("corrupt");
|
|
20956
22067
|
}
|
|
20957
|
-
return { metadata, decoded };
|
|
22068
|
+
return { metadata: metadata2, decoded };
|
|
20958
22069
|
}
|
|
20959
22070
|
function terminalOutcome(events) {
|
|
20960
22071
|
const last = events.at(-1);
|
|
@@ -21006,7 +22117,7 @@ function canDeleteTerminalRun(runDir, runID, now) {
|
|
|
21006
22117
|
return now >= lease.expiresAt;
|
|
21007
22118
|
}
|
|
21008
22119
|
var createFsLifecycleJournal = (options) => {
|
|
21009
|
-
const configuredRoot =
|
|
22120
|
+
const configuredRoot = resolve11(options.root);
|
|
21010
22121
|
const now = options.now ?? Date.now;
|
|
21011
22122
|
const mutateRun = options.withMutationLock ?? withRunMutationLock;
|
|
21012
22123
|
return {
|
|
@@ -21032,7 +22143,7 @@ var createFsLifecycleJournal = (options) => {
|
|
|
21032
22143
|
mkdirSync3(stagingPath);
|
|
21033
22144
|
const writerToken = issueWriterToken();
|
|
21034
22145
|
const eventAt = now();
|
|
21035
|
-
const
|
|
22146
|
+
const metadata2 = parseLifecycleRunMetadata({
|
|
21036
22147
|
...parsedInput,
|
|
21037
22148
|
version: 1,
|
|
21038
22149
|
createdAt: eventAt
|
|
@@ -21048,7 +22159,7 @@ var createFsLifecycleJournal = (options) => {
|
|
|
21048
22159
|
executionAuthority: parsedInput.executionAuthority,
|
|
21049
22160
|
root: parsedInput.root
|
|
21050
22161
|
});
|
|
21051
|
-
writeDurable2(join15(stagingPath, METADATA_FILE), `${JSON.stringify(
|
|
22162
|
+
writeDurable2(join15(stagingPath, METADATA_FILE), `${JSON.stringify(metadata2)}
|
|
21052
22163
|
`);
|
|
21053
22164
|
writeDurable2(join15(stagingPath, EVENTS_FILE), encodeLifecycleJournal([event]));
|
|
21054
22165
|
writeDurable2(join15(stagingPath, OWNER_FILE2), `${JSON.stringify(lease)}
|
|
@@ -21064,7 +22175,7 @@ var createFsLifecycleJournal = (options) => {
|
|
|
21064
22175
|
stagingPath = undefined;
|
|
21065
22176
|
return ok({
|
|
21066
22177
|
handle: { runID, writerToken },
|
|
21067
|
-
metadata,
|
|
22178
|
+
metadata: metadata2,
|
|
21068
22179
|
event,
|
|
21069
22180
|
lease,
|
|
21070
22181
|
head: 1
|
|
@@ -21638,8 +22749,8 @@ async function readOpencodeVersion(serverUrl, options = {}) {
|
|
|
21638
22749
|
}
|
|
21639
22750
|
var DEFAULT_OPENCODE_VERSION_BACKOFF_MS = [50, 250];
|
|
21640
22751
|
function defaultSleep(ms) {
|
|
21641
|
-
return new Promise((
|
|
21642
|
-
setTimeout(
|
|
22752
|
+
return new Promise((resolve12) => {
|
|
22753
|
+
setTimeout(resolve12, ms);
|
|
21643
22754
|
});
|
|
21644
22755
|
}
|
|
21645
22756
|
function createLazyOpencodeVersionReader(serverUrl, options = {}) {
|
|
@@ -21925,6 +23036,9 @@ async function listConfiguredOpencodeInventory(ctx) {
|
|
|
21925
23036
|
providerID: model.providerID,
|
|
21926
23037
|
modelID: model.id
|
|
21927
23038
|
};
|
|
23039
|
+
if (typeof model.api?.id === "string" && model.api.id.length > 0 && model.api.id === model.api.id.trim() && model.api.id !== model.id) {
|
|
23040
|
+
configuredModel.apiModelID = model.api.id;
|
|
23041
|
+
}
|
|
21928
23042
|
if (typeof model.capabilities?.toolcall === "boolean") {
|
|
21929
23043
|
configuredModel.supportsTools = model.capabilities.toolcall;
|
|
21930
23044
|
}
|
|
@@ -21994,12 +23108,20 @@ var server = async (ctx, rawOptions) => {
|
|
|
21994
23108
|
const injectMemory = await buildMemoryInjectorFromConfig(config, storage, diagnostics.warn("memory-runtime-warning", { toast: false }));
|
|
21995
23109
|
const sessionTracker = createSessionTracker();
|
|
21996
23110
|
const orchestratedModelOwnership = createOrchestratedModelOwnership();
|
|
23111
|
+
const modelResidency = createModelResidencyGuard(config, {
|
|
23112
|
+
fetch: globalThis.fetch,
|
|
23113
|
+
...ctx.client.config?.providers === undefined ? {} : {
|
|
23114
|
+
resolveApiModelID: cache.resolveApiModelID,
|
|
23115
|
+
modelInventoryReady: ensureAvailability
|
|
23116
|
+
}
|
|
23117
|
+
});
|
|
21997
23118
|
const resolveAgentRole = async (agentName) => {
|
|
21998
23119
|
const entry = (await readRoutingRosterEntries(storage)).find((candidate) => candidate.agentName === agentName);
|
|
21999
23120
|
return entry?.roleID;
|
|
22000
23121
|
};
|
|
22001
23122
|
const hooks = createHooks(config, cache.get, injectMemory === undefined ? {
|
|
22002
23123
|
sink,
|
|
23124
|
+
modelResidency,
|
|
22003
23125
|
beforeRoute: ensureAvailability,
|
|
22004
23126
|
capabilityProfiles,
|
|
22005
23127
|
orchestratedModelOwnership,
|
|
@@ -22007,6 +23129,7 @@ var server = async (ctx, rawOptions) => {
|
|
|
22007
23129
|
onRoute: (sid, model) => sessionTracker.trackRoutedModel(sid, model)
|
|
22008
23130
|
} : {
|
|
22009
23131
|
sink,
|
|
23132
|
+
modelResidency,
|
|
22010
23133
|
beforeRoute: ensureAvailability,
|
|
22011
23134
|
capabilityProfiles,
|
|
22012
23135
|
injectMemory,
|
|
@@ -22127,7 +23250,7 @@ var server = async (ctx, rawOptions) => {
|
|
|
22127
23250
|
if (runtime === undefined) {
|
|
22128
23251
|
return;
|
|
22129
23252
|
}
|
|
22130
|
-
return withReportedModelSlots(runtime, reportedSlotsByRuntime.get(runtimeId));
|
|
23253
|
+
return withReportedModelSlots(runtime, reportedSlotsByRuntime.get(runtimeId), localModelAliases(runtime.defaultModel.providerID, cache.get()));
|
|
22131
23254
|
};
|
|
22132
23255
|
const runtimeLimiter = createRuntimeConcurrencyLimiter({
|
|
22133
23256
|
capacityFor: (key2) => {
|
|
@@ -22163,8 +23286,8 @@ var server = async (ctx, rawOptions) => {
|
|
|
22163
23286
|
lifecycleRecorder,
|
|
22164
23287
|
abortGraceMs: DEFAULT_ABORT_GRACE_MS,
|
|
22165
23288
|
statusPollMs: DEFAULT_STATUS_POLL_MS,
|
|
22166
|
-
delay: (ms) => new Promise((
|
|
22167
|
-
setTimeout(
|
|
23289
|
+
delay: (ms) => new Promise((resolve12) => {
|
|
23290
|
+
setTimeout(resolve12, ms);
|
|
22168
23291
|
}),
|
|
22169
23292
|
warn: diagnostics.warn("unknown-role")
|
|
22170
23293
|
});
|
|
@@ -22172,7 +23295,27 @@ var server = async (ctx, rawOptions) => {
|
|
|
22172
23295
|
config,
|
|
22173
23296
|
storage,
|
|
22174
23297
|
now,
|
|
22175
|
-
localRuntimeReachable,
|
|
23298
|
+
localRuntimeReachable: async (runtime, signal) => {
|
|
23299
|
+
if (localRuntimeKind(runtime) === "lemonade") {
|
|
23300
|
+
if (ctx.client.config?.providers !== undefined)
|
|
23301
|
+
await ensureAvailability();
|
|
23302
|
+
signal?.throwIfAborted();
|
|
23303
|
+
const target = modelResidency.localTarget(resolveMemorySemantic(config).extraction.model ?? runtime.defaultModel);
|
|
23304
|
+
const response = await target.fetch(`${target.baseURL}/health`, {
|
|
23305
|
+
method: "GET",
|
|
23306
|
+
...signal === undefined ? {} : { signal }
|
|
23307
|
+
});
|
|
23308
|
+
return response.ok;
|
|
23309
|
+
}
|
|
23310
|
+
const snapshots = await registry.probe([runtime]);
|
|
23311
|
+
rememberReportedSlots(snapshots);
|
|
23312
|
+
return anyRuntimeReachable(snapshots);
|
|
23313
|
+
},
|
|
23314
|
+
resolveExtractionTarget: async (model) => {
|
|
23315
|
+
if (ctx.client.config?.providers !== undefined)
|
|
23316
|
+
await ensureAvailability();
|
|
23317
|
+
return modelResidency.localTarget(model);
|
|
23318
|
+
},
|
|
22176
23319
|
fetch: globalThis.fetch,
|
|
22177
23320
|
warn: diagnostics.warn("memory-extraction-warning", { toast: false })
|
|
22178
23321
|
});
|
|
@@ -22184,23 +23327,43 @@ var server = async (ctx, rawOptions) => {
|
|
|
22184
23327
|
options: rawOptions
|
|
22185
23328
|
})
|
|
22186
23329
|
});
|
|
23330
|
+
const reload = createReloadController({
|
|
23331
|
+
directory: ctx.directory,
|
|
23332
|
+
client: ctx.client,
|
|
23333
|
+
notify: (code) => diagnostics.emit({
|
|
23334
|
+
code,
|
|
23335
|
+
level: code === "reload-timeout" || code === "reload-status-failed" || code === "reload-dispose-failed" || code === "reload-unconfirmed" ? "warn" : "info"
|
|
23336
|
+
}, { toast: code !== "reload-queued" })
|
|
23337
|
+
});
|
|
22187
23338
|
return {
|
|
22188
23339
|
...hooks,
|
|
23340
|
+
"chat.message": async (input, output) => {
|
|
23341
|
+
reload.userTurn(input.sessionID);
|
|
23342
|
+
await hooks["chat.message"]?.(input, output);
|
|
23343
|
+
},
|
|
23344
|
+
dispose: async () => {
|
|
23345
|
+
reload.dispose();
|
|
23346
|
+
await hooks.dispose?.();
|
|
23347
|
+
},
|
|
22189
23348
|
tool: {
|
|
22190
23349
|
openteam: createCommandTool(cliDeps),
|
|
22191
23350
|
"openteam-console": createConsoleTool(),
|
|
22192
23351
|
"openteam-graph": graphSurface.definition,
|
|
22193
23352
|
"openteam-orchestrate": orchestrateTool,
|
|
22194
23353
|
"openteam-memory": memoryTool,
|
|
22195
|
-
"openteam-register-cast": registerCastTool
|
|
23354
|
+
"openteam-register-cast": registerCastTool,
|
|
23355
|
+
"openteam-reload": reload.tool
|
|
22196
23356
|
},
|
|
22197
23357
|
"tool.execute.before": async (input) => {
|
|
22198
23358
|
toolcalls.before(input);
|
|
22199
23359
|
},
|
|
22200
23360
|
"tool.execute.after": async (input) => {
|
|
22201
23361
|
await toolcalls.after(input);
|
|
23362
|
+
if (input.tool === "openteam-reload")
|
|
23363
|
+
reload.toolCompleted(input.sessionID);
|
|
22202
23364
|
},
|
|
22203
23365
|
event: async ({ event }) => {
|
|
23366
|
+
reload.event(event);
|
|
22204
23367
|
if (event.type === "session.created" || event.type === "session.idle") {
|
|
22205
23368
|
cache.refresh();
|
|
22206
23369
|
}
|