@amaster.ai/employee-runtime-connector 0.1.1-beta.22 → 0.1.1-beta.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -32,6 +32,20 @@ The source of truth lives under this package's `src/` directory. The package bui
32
32
 
33
33
  Runtime code belongs in the container image. Persist only connector state, the result outbox, and workspaces under the configured state directory.
34
34
 
35
+ ## Contracted Pi model calls
36
+
37
+ Pi `model_call` commands with `model_call_output_contract_v1` keep provider and
38
+ model selection paired with the output ceiling. Command target fields have the
39
+ highest precedence, followed by `AMASTER_PI_PROVIDER` / `AMASTER_PI_MODEL`, then
40
+ the Pi profile's `defaultProvider` / `defaultModel`. Each selected precedence
41
+ layer must be a complete provider/model pair: a partial command or runtime
42
+ override fails closed instead of silently falling through to a lower-precedence
43
+ default. The daemon copies only the normalized default pair into the isolated
44
+ one-shot profile, validates that the resolved model exists, applies
45
+ `maxOutputTokens` to that exact model, and records the resolved target and source
46
+ in command-result diagnostics. Missing or unknown targets also fail closed
47
+ before Pi is spawned.
48
+
35
49
  ## Pi tool-argument transport guard
36
50
 
37
51
  `AMASTER_PI_TOOL_ARGUMENT_GUARD_MODE` defaults to `shadow`; supported values are
@@ -2008,13 +2008,7 @@ function syncAmasterProviderFiles(agentDir, executorEnv) {
2008
2008
  function normalizePiModelId(modelId) {
2009
2009
  return readString(modelId)?.replace(/:(?:off|minimal|low|medium|high|xhigh|max)$/i, "") ?? null;
2010
2010
  }
2011
- function applyModelCallOutputContract(agentDir, providerId, modelId, maxOutputTokens) {
2012
- const provider = readString(providerId);
2013
- const model = normalizePiModelId(modelId);
2014
- const tokenLimit = Number(maxOutputTokens);
2015
- if (!provider || !model || !Number.isSafeInteger(tokenLimit) || tokenLimit <= 0) {
2016
- throw new Error("pi_model_call_output_contract_invalid");
2017
- }
2011
+ function assertPiModelConfigured(agentDir, provider, model) {
2018
2012
  const modelsPath = join3(agentDir, "models.json");
2019
2013
  const config = readJsonFile(modelsPath);
2020
2014
  const providers = asRecord(config.providers);
@@ -2025,6 +2019,42 @@ function applyModelCallOutputContract(agentDir, providerId, modelId, maxOutputTo
2025
2019
  if (!configuredModelExists && !(model in existingOverrides)) {
2026
2020
  throw new Error(`pi_model_call_model_missing: ${provider}/${model}`);
2027
2021
  }
2022
+ return { modelsPath, config, providers, providerConfig, existingOverrides };
2023
+ }
2024
+ function resolvePiModelCallTarget(agentDir, providerId, modelId, explicitSource = "command") {
2025
+ const explicitProvider = readString(providerId);
2026
+ const explicitModel = normalizePiModelId(modelId);
2027
+ if (Boolean(explicitProvider) !== Boolean(explicitModel)) {
2028
+ throw new Error("pi_model_call_target_partial");
2029
+ }
2030
+ let provider = explicitProvider;
2031
+ let model = explicitModel;
2032
+ let source = explicitSource;
2033
+ if (!provider || !model) {
2034
+ const settings = readJsonFile(join3(agentDir, "settings.json"));
2035
+ const defaultProvider = readString(settings.defaultProvider);
2036
+ const defaultModel = normalizePiModelId(settings.defaultModel);
2037
+ if (Boolean(defaultProvider) !== Boolean(defaultModel)) {
2038
+ throw new Error("pi_model_call_default_partial");
2039
+ }
2040
+ if (!defaultProvider || !defaultModel) {
2041
+ throw new Error("pi_model_call_default_missing");
2042
+ }
2043
+ provider = defaultProvider;
2044
+ model = defaultModel;
2045
+ source = "pi_settings_default";
2046
+ }
2047
+ assertPiModelConfigured(agentDir, provider, model);
2048
+ return { provider, model, source };
2049
+ }
2050
+ function applyModelCallOutputContract(agentDir, providerId, modelId, maxOutputTokens) {
2051
+ const provider = readString(providerId);
2052
+ const model = normalizePiModelId(modelId);
2053
+ const tokenLimit = Number(maxOutputTokens);
2054
+ if (!provider || !model || !Number.isSafeInteger(tokenLimit) || tokenLimit <= 0) {
2055
+ throw new Error("pi_model_call_output_contract_invalid");
2056
+ }
2057
+ const { modelsPath, config, providers, providerConfig, existingOverrides } = assertPiModelConfigured(agentDir, provider, model);
2028
2058
  writeJsonFileAtomic(modelsPath, {
2029
2059
  ...config,
2030
2060
  providers: {
@@ -4401,24 +4431,6 @@ function continuationText(context) {
4401
4431
  if (!body) return "";
4402
4432
  return [readString(summary.title), body].filter(Boolean).join("\n");
4403
4433
  }
4404
- function onDemandRefs(input) {
4405
- const context = asRecord(input.context);
4406
- const issue = asRecord(context.paperclipIssue);
4407
- const wake = asRecord(context.paperclipWake);
4408
- const refs = [
4409
- readString(issue.id) ? `issue:${readString(issue.id)}` : null,
4410
- ...commentRefs(context).map((id) => `comment:${id}`),
4411
- ...(Array.isArray(context.childIssueSummaries) ? context.childIssueSummaries : []).map((entry) => readString(asRecord(entry).id)).filter(Boolean).map((id) => `child_issue:${id}`),
4412
- ...(Array.isArray(wake.workProducts) ? wake.workProducts : []).map((entry) => readString(asRecord(entry).id)).filter(Boolean).map((id) => `work_product:${id}`)
4413
- ];
4414
- const unique = [...new Set(refs.filter(Boolean))];
4415
- if (unique.length === 0) return "";
4416
- return [
4417
- "Large context objects are intentionally omitted from this prompt.",
4418
- "Use managed typed read tools when more detail is required; preserve returned source and freshness metadata.",
4419
- ...unique.map((ref) => `- ${ref}`)
4420
- ].join("\n");
4421
- }
4422
4434
  function governedReadSection(context) {
4423
4435
  const reads = Array.isArray(context.governedReadResults) ? context.governedReadResults : [];
4424
4436
  if (reads.length === 0) return { content: "", provenance: [] };
@@ -4828,6 +4840,7 @@ function fixedRules(input, includeIssueLine) {
4828
4840
  "Before changing the task status to done, audit every explicit requirement in the task against the final evidence. A successful tool or document write proves delivery, not acceptance: inspect the delivered content for required sections, diagrams, tables, and factual constraints.",
4829
4841
  "Do not leave stale in-progress wording such as \u201Ccurrent run\u201D in a terminal deliverable; rewrite it to the final observed state. Do not list finalization itself as remaining or next work in a terminal deliverable.",
4830
4842
  serverOwnedBusinessOutcomeReview ? "If any requirement is missing or cannot be verified, do not mark done or request final completion or Business Outcome review. Keep the issue in_progress with the exact gap and next owner. An intermediate review remains available only for an exact document revision that must be approved before execution can continue: use create_interaction with kind request_confirmation, payload.resolutionMode review, and purposeCode review_document_revision; never use that interaction as final completion or Outcome acceptance." : "If anything is missing, do not mark done. `update_parent` cannot write `in_review` or `blocked`. Human review: create_interaction kind request_confirmation with payload.resolutionMode review. Required platform/provider/external action needs a typed interaction or first-class blocker; otherwise keep todo with the gap and owner.",
4843
+ "A create_interaction result with status=pending or mustEndRun=true establishes human attention and is the final mutation of this run. End the run immediately: do not publish a Delivery Manifest, update a document or task, or submit any other mutation. Continue only in the new run created after the interaction is resolved.",
4831
4844
  DEADLINE_POSTURE_GUARD,
4832
4845
  "Do not install operating-system or user-global packages, and do not use host package managers such as brew, apt, yum, or global pip/npm installs. Use tools already available or workspace-local dependencies or virtual environments. If a required renderer or evaluator is unavailable, keep the source artifact, record the exact verification gap, and do not mutate the host.",
4833
4846
  `- command id: ${input.commandId}`,
@@ -5164,30 +5177,26 @@ function overflowDependencyRefsText(overflowRefs) {
5164
5177
  ...overflowRefs.map((ref) => `- issue ${JSON.stringify(ref.selector)}, key ${JSON.stringify(ref.key)}`)
5165
5178
  ].join("\n");
5166
5179
  }
5167
- function taskCommentRefGuidance(input) {
5180
+ function taskCommentRefGuidance(input, taskText) {
5168
5181
  if (!input.hasGovernedMcp || !readString(input.issueId)) return "";
5182
+ if (!/\[comment body (?:omitted|truncated)[^\]]*comment:[^\s\]]+\]/i.test(taskText)) return "";
5169
5183
  const call = readIssueEvidenceCommentCallText(input.issueId, "<id>", input);
5170
5184
  return `References like comment:<id> above mark truncated comment bodies. Fetch the full text before relying on them \u2014 ${call} (replace <id> with the referenced comment id).`;
5171
5185
  }
5172
- function piMcpProxyExamplesText(input) {
5186
+ function piMcpUsageText(input) {
5173
5187
  if (!input.hasGovernedMcp || input.executorKind !== "pi" || !managedPiMcpProxyAvailable(input) || isRecoveryWakeReason(input.wakeReason)) return "";
5174
- const hybrid = input.managedMcpToolMode === "hybrid";
5175
5188
  const proxy = (tool, args) => JSON.stringify({
5176
5189
  server: "amaster",
5177
5190
  tool,
5178
5191
  args: JSON.stringify(args)
5179
5192
  });
5180
5193
  return [
5181
- hybrid ? "For governed tools not exposed in the direct typed list, use the outer `mcp` proxy. Before the first long-tail proxy call, describe that exact canonical tool; `args` is the stringified inner canonical object and must never be object-valued." : "The Pi native tool is the outer `mcp` proxy. Emit these as actual tool calls; `args` is the stringified inner canonical object. Pi validates this string schema before extension hooks, so never send object-valued `args`:",
5194
+ "This run uses the outer `mcp` proxy for Governed MCP calls. Emit actual tool calls; `args` is the stringified inner canonical object. Pi validates this string schema before extension hooks, so never send object-valued `args`.",
5195
+ "Before the first write, describe that exact canonical action and use the returned schema; do not infer write arguments from this example.",
5182
5196
  "Keep review payload strings short. Reference the exact document key and revision in `target`; do not duplicate the reviewed document body in `prompt` or `detailsMarkdown`.",
5183
5197
  "payload.supersedesInteractionId is invalid. provenance.supersedesInteractionId is only for replacing a currently pending governed interaction; after changes_requested or rejected resolution, do not send a supersession id.",
5184
5198
  "update_parent.comment creates a separate persistent issue comment. Omit it when add_comment already recorded the message.",
5185
- ...!hybrid ? [`- describe: ${proxy("runtime_action.describe", { schemaVersion: "runtime-action-v1", actionType: "update_parent" })}`] : [],
5186
- `- submit: ${proxy("runtime_action.submit", { schemaVersion: "runtime-action-v1", idempotencyKey: "task-123-progress", action: { type: "update_parent", status: "in_progress" } })}`,
5187
- `- submit intermediate document review interaction: ${proxy("runtime_action.submit", { schemaVersion: "runtime-action-v1", idempotencyKey: "task-123-review", action: { type: "create_interaction", kind: "request_confirmation", continuationPolicy: "wake_assignee_on_accept", provenance: { purposeCode: "review_document_revision", requirementRefs: ["acceptance:document_review"], attentionOwner: { kind: "board", id: "board" }, epochKey: "document_revision:22222222-2222-4222-8222-222222222222" }, payload: { version: 1, resolutionMode: "review", prompt: "Review `plan` revision 1.", target: { type: "issue_document", issueId: "11111111-1111-4111-8111-111111111111", documentId: "33333333-3333-4333-8333-333333333333", key: "plan", revisionId: "22222222-2222-4222-8222-222222222222", revisionNumber: 1 } } } })}`,
5188
- `- plan: ${proxy("runtime_action.plan", { schemaVersion: "runtime-action-v1", idempotencyKey: "task-123-plan", actions: [{ type: "update_parent", status: "in_progress" }] })}`,
5189
- `- commit the returned plan revision: ${proxy("runtime_action.commit", { schemaVersion: "runtime-action-v1", planId: "11111111-1111-4111-8111-111111111111", revision: "plan-revision-1" })}`,
5190
- ...!hybrid ? [`- read document: ${proxy("amaster.read_issue_document", { issueId: "AM-123", key: "plan" })}`] : []
5199
+ `- minimal envelope example: ${proxy("runtime_action.describe", { schemaVersion: "runtime-action-v1", actionType: "update_parent" })}`
5191
5200
  ].join("\n");
5192
5201
  }
5193
5202
  function piDirectTypedToolsText(input) {
@@ -5198,9 +5207,8 @@ function piDirectTypedToolsText(input) {
5198
5207
  return "Direct typed governed tools are unavailable because the run catalog snapshot is empty. Do not guess a proxy or tool name.";
5199
5208
  }
5200
5209
  return [
5201
- input.managedMcpToolMode === "hybrid" ? "This run exposes the attested high-frequency Governed MCP tools below as direct typed tools. Call these exact names with object arguments and do not send them through the `mcp` proxy." : "This run uses the attested direct typed Governed MCP surface below. Call these exact names with object arguments; do not call the `mcp` proxy and do not stringify an inner argument envelope.",
5202
- ...tools.map((tool) => `- ${tool.name}${tool.description ? `: ${tool.description}` : ""}`),
5203
- input.managedMcpToolMode === "hybrid" ? "For a canonical tool not listed above, use the single managed `mcp` proxy only after exact describe. Never infer an alias, use REST, or bypass the governed Gateway." : "A tool not listed above is unavailable in this run. Do not infer a namespace or fall back to REST/bare MCP."
5210
+ input.managedMcpToolMode === "hybrid" ? "Use the attested direct typed tools already present in the provider tool definitions with object arguments; do not duplicate them through the `mcp` proxy." : "Use only the attested direct typed tools already present in the provider tool definitions. Call their exact names with object arguments; do not call the `mcp` proxy and do not stringify an inner argument envelope.",
5211
+ input.managedMcpToolMode === "hybrid" ? "For a canonical tool absent from those definitions, first use the direct typed `runtime_action_describe`, then call the single managed `mcp` proxy with stringified inner `args`. Never infer an alias, use REST, or bypass the governed Gateway." : "A tool absent from the provider tool definitions is unavailable in this run. Do not infer a namespace or fall back to REST/bare MCP."
5204
5212
  ].join("\n");
5205
5213
  }
5206
5214
  function sectionText(section) {
@@ -5254,7 +5262,7 @@ var CONTEXT_AVAILABILITY_SECTION_TITLES = Object.freeze({
5254
5262
  runtime_decomposition_requirement: "Required Task Decomposition",
5255
5263
  task_context_authority: "Task Context Authority",
5256
5264
  verified_company_context: "Verified Company Context",
5257
- pi_mcp_proxy_examples: "Pi MCP Proxy Examples",
5265
+ pi_mcp_usage: "Pi Governed MCP Usage",
5258
5266
  governed_reads: "Governed External Reads",
5259
5267
  optional_task_wiki_context: "Optional Company Wiki Context",
5260
5268
  agent_instructions: "Agent Instructions",
@@ -5286,14 +5294,6 @@ function projectModelContextAvailability(manifestSections) {
5286
5294
  );
5287
5295
  coveredSections.push(...budgetOmissions);
5288
5296
  }
5289
- const rawSnapshot = bySection.get("raw_snapshot");
5290
- const onDemandRefs2 = bySection.get("on_demand_refs");
5291
- if (rawSnapshot?.omitted === true && rawSnapshot.truncationReason === "on_demand_large_object" && Number(rawSnapshot.originalChars ?? 0) > 0 && (!onDemandRefs2 || onDemandRefs2.omitted === true)) {
5292
- lines.push(
5293
- "Additional raw run context was intentionally not inlined and no managed on-demand reference was provided. Do not assume that omitted details are absent."
5294
- );
5295
- coveredSections.push("raw_snapshot");
5296
- }
5297
5297
  return {
5298
5298
  content: lines.join("\n"),
5299
5299
  coveredSections: [...new Set(coveredSections)]
@@ -5384,8 +5384,8 @@ function compileCommandPromptWithManifest(input, options = {}) {
5384
5384
  ${resolvedDependencies.details.content}` : ""
5385
5385
  ].filter(Boolean).join("\n\n") : "";
5386
5386
  const piDirectTypedTools = piDirectTypedToolsText(input);
5387
- const piMcpProxyExamples = [
5388
- resolvedDependencies.required.content ? "" : piMcpProxyExamplesText(input),
5387
+ const piMcpUsage = [
5388
+ input.managedMcpToolMode === "proxy_only" && !resolvedDependencies.required.content ? piMcpUsageText(input) : "",
5389
5389
  piDirectTypedTools
5390
5390
  ].filter(Boolean).join("\n");
5391
5391
  const deliveryReadinessContent = runtimeDeliveryReadinessText(context, input);
@@ -5395,7 +5395,7 @@ ${resolvedDependencies.details.content}` : ""
5395
5395
  { name: "recovery_instruction", title: "Recovery Instruction", priority: 100, sourceRef: `run:${input.runId ?? "unknown"}`, content: completeRecoveryInstruction, truncationReason: completeRecoveryInstruction ? null : "mode_selection" },
5396
5396
  { name: "approval_continuation", title: "Approved Runtime Action Continuation", priority: 99, sourceRef: `run:${input.runId ?? "unknown"}`, content: approvalContinuationText(input), truncationReason: mode === "continuation" ? null : "mode_selection" },
5397
5397
  { name: "wake_comments", title: wakeDeltaTitle, priority: interactionResolution ? 99 : 95, sourceRef: wakeDeltaSourceRefs, originalContent: wakeDeltaOriginal, content: wakeDeltaContent, truncationReason: commentsSelected ? null : "duplicate_task_context" },
5398
- { name: "task", title: "Task Context", priority: 90, sourceRef: `issue:${input.issueId ?? "unknown"}`, originalContent: [taskText, taskCommentRefGuidance(input)].filter(Boolean).join("\n"), content: includeTask ? [taskText, taskCommentRefGuidance(input)].filter(Boolean).join("\n") : "", truncationReason: includeTask ? null : "mode_selection" },
5398
+ { name: "task", title: "Task Context", priority: 90, sourceRef: `issue:${input.issueId ?? "unknown"}`, originalContent: [taskText, taskCommentRefGuidance(input, taskText)].filter(Boolean).join("\n"), content: includeTask ? [taskText, taskCommentRefGuidance(input, taskText)].filter(Boolean).join("\n") : "", truncationReason: includeTask ? null : "mode_selection" },
5399
5399
  ...governedBusinessState ? [{ name: "governed_business_state", title: "Governed Business State", priority: 99, ...governedBusinessState }] : [],
5400
5400
  { name: "continuation_summary", title: "Continuation Summary", priority: 97, sourceRef: readString(asRecord(context.paperclipContinuationSummary).key) ?? `issue:${input.issueId ?? "unknown"}`, observedAt: readString(asRecord(context.paperclipContinuationSummary).updatedAt), originalContent: continuationSummary, content: mode === "cold" ? "" : continuationSummary, truncationReason: mode === "cold" ? "mode_selection" : null },
5401
5401
  ...resolvedDependencyContent ? [{
@@ -5412,18 +5412,18 @@ ${resolvedDependencies.details.content}` : ""
5412
5412
  { name: "runtime_decomposition_requirement", title: "Required Task Decomposition", priority: 98, sourceRef: `issue:${input.issueId ?? "unknown"}`, content: runtimeDecompositionRequirementText(context) },
5413
5413
  ...taskContextAuthority ? [{ name: "task_context_authority", title: "Task Context Authority", priority: 98, ...taskContextAuthority }] : [],
5414
5414
  ...verifiedCompanyContext.content ? [{ name: "verified_company_context", title: "Verified Company Context", priority: 96, sourceRef: verifiedCompanyContext.sourceRef, observedAt: verifiedCompanyContext.observedAt, freshness: { kind: "run_snapshot" }, content: verifiedCompanyContext.content }] : [],
5415
- ...piMcpProxyExamples ? [{
5416
- name: "pi_mcp_proxy_examples",
5417
- title: piDirectTypedTools ? "Pi Governed MCP Tools" : "Pi MCP Proxy Examples",
5415
+ ...piMcpUsage ? [{
5416
+ name: "pi_mcp_usage",
5417
+ title: "Pi Governed MCP Usage",
5418
5418
  priority: 96,
5419
5419
  sourceRef: "amaster_governed_mcp_proxy_contract",
5420
- content: piMcpProxyExamples
5420
+ content: piMcpUsage
5421
5421
  }] : [],
5422
5422
  { name: "governed_reads", title: "Governed External Reads", priority: 88, sourceRef: governedReads.provenance.map((entry) => entry.sourceRef), observedAt: governedReads.provenance.map((entry) => entry.observedAt), freshness: governedReads.provenance.map((entry) => entry.freshness), scope: governedReads.provenance.map((entry) => entry.scope), content: governedReads.content },
5423
5423
  ...optionalTaskWikiContext ? [optionalTaskWikiContext] : [],
5424
5424
  { name: "agent_instructions", title: "Agent Instructions", priority: 100, sourceRef: "agent_instructions_bundle", content: readString(input.agentInstructions) ?? "" },
5425
5425
  { name: "attachments", title: "Materialized Inputs", priority: 80, sourceRef: "materialized_attachments", content: readString(input.attachmentsText) ?? "" },
5426
- { name: "on_demand_refs", title: "On-demand Context References", priority: 70, sourceRef: `issue:${input.issueId ?? "unknown"}`, content: [onDemandRefs(input), overflowDependencyRefsText(resolvedDependencies.overflowRefs)].filter(Boolean).join("\n") },
5426
+ { name: "on_demand_refs", title: "On-demand Context References", priority: 70, sourceRef: `issue:${input.issueId ?? "unknown"}`, content: overflowDependencyRefsText(resolvedDependencies.overflowRefs) },
5427
5427
  { name: "raw_snapshot", title: "Raw Context Snapshot", priority: 0, sourceRef: `run:${input.runId ?? "unknown"}`, originalChars: jsonCharLength(context), content: "", truncationReason: "on_demand_large_object" }
5428
5428
  ];
5429
5429
  const seenContent = /* @__PURE__ */ new Set();
@@ -5529,10 +5529,7 @@ function renderAgentInstructionsBundle(bundle, delivery) {
5529
5529
  ].join("\n");
5530
5530
  }
5531
5531
  if (resolvedDelivery.mode === "executor_auto_load") {
5532
- return [
5533
- materialized,
5534
- "This executor has already loaded ./AGENTS.md through its project-instruction channel. Follow it for the whole run; do not read it again merely to initialize. Read sibling instruction files only when ./AGENTS.md references them or the current task requires them."
5535
- ].join("\n");
5532
+ return "";
5536
5533
  }
5537
5534
  return [
5538
5535
  materialized,
@@ -10255,7 +10252,7 @@ function assertSourceAcquisitionRuntimeAuthority({
10255
10252
  }
10256
10253
 
10257
10254
  // src/amaster-runtime-daemon.mjs
10258
- var CONNECTOR_VERSION = "0.1.1-beta.22";
10255
+ var CONNECTOR_VERSION = "0.1.1-beta.23";
10259
10256
  var CONNECTOR_CONTRACT_VERSION = "2026-06-04.v1";
10260
10257
  var SOURCE_ACQUISITION_CAPABILITY = "source_acquisition_v1";
10261
10258
  var SOURCE_ACQUISITION_PROFILE_VERSION = "source_acquisition_v1";
@@ -11889,7 +11886,30 @@ function copyPiModelCallConfig(sourceRoot, targetRoot, fileName, required) {
11889
11886
  copyFileSync3(source, target);
11890
11887
  chmodSync6(target, 384);
11891
11888
  }
11892
- function preparePiModelCallProfile(commandId, baseEnv) {
11889
+ function copyPiModelCallDefaults(sourceRoot, targetRoot) {
11890
+ const source = join15(sourceRoot, "settings.json");
11891
+ if (!existsSync14(source)) return;
11892
+ const sourceStat = lstatSync7(source);
11893
+ if (!sourceStat.isFile() || sourceStat.isSymbolicLink()) {
11894
+ throw new Error("pi_model_call_profile_unsafe: settings.json");
11895
+ }
11896
+ let settings;
11897
+ try {
11898
+ settings = asRecord(JSON.parse(readFileSync11(source, "utf8")));
11899
+ } catch {
11900
+ throw new Error("pi_model_call_profile_invalid: settings.json");
11901
+ }
11902
+ const defaultProvider = readString(settings.defaultProvider);
11903
+ const defaultModel = normalizePiModelId(settings.defaultModel);
11904
+ const target = join15(targetRoot, "settings.json");
11905
+ writeFileSync9(target, `${JSON.stringify({
11906
+ ...defaultProvider ? { defaultProvider } : {},
11907
+ ...defaultModel ? { defaultModel } : {}
11908
+ }, null, 2)}
11909
+ `, { mode: 384 });
11910
+ chmodSync6(target, 384);
11911
+ }
11912
+ function preparePiModelCallProfile(commandId, baseEnv, options = {}) {
11893
11913
  const sourceRoot = readString(process.env.PI_CODING_AGENT_DIR) ?? readString(process.env.PI_AGENT_HOME) ?? readString(process.env["AMASTER-CLI_CODING_AGENT_DIR"]);
11894
11914
  if (!sourceRoot) throw new Error("pi_model_call_profile_missing: source Pi home");
11895
11915
  const sourceStat = lstatSync7(sourceRoot);
@@ -11907,6 +11927,7 @@ function preparePiModelCallProfile(commandId, baseEnv) {
11907
11927
  try {
11908
11928
  copyPiModelCallConfig(sourceRoot, agentDir, "models.json", true);
11909
11929
  copyPiModelCallConfig(sourceRoot, agentDir, "auth.json", false);
11930
+ if (options.includeDefaults === true) copyPiModelCallDefaults(sourceRoot, agentDir);
11910
11931
  return {
11911
11932
  profileRoot,
11912
11933
  env: {
@@ -11991,8 +12012,9 @@ function buildExecutorInvocation(executor, command = {}, workspace = null, optio
11991
12012
  if (executor.kind === "pi") {
11992
12013
  const args = ["--mode", "json"];
11993
12014
  const responseContract = options.responseContract ?? null;
11994
- const provider = readString(payload.provider) ?? readString(process.env.AMASTER_PI_PROVIDER);
11995
- const configuredModel = readString(payload.model) ?? readString(process.env.AMASTER_PI_MODEL);
12015
+ const modelTarget = asRecord(options.modelTarget);
12016
+ const provider = readString(modelTarget.provider) ?? readString(payload.provider) ?? readString(process.env.AMASTER_PI_PROVIDER);
12017
+ const configuredModel = readString(modelTarget.model) ?? readString(payload.model) ?? readString(process.env.AMASTER_PI_MODEL);
11996
12018
  const model = responseContract ? normalizePiModelId(configuredModel) : configuredModel;
11997
12019
  if (provider) args.push("--provider", provider);
11998
12020
  if (model) args.push("--model", model);
@@ -12088,7 +12110,6 @@ async function executeModelCallCommand(config, command, signal) {
12088
12110
  throw new Error("model_call command requires a prompt");
12089
12111
  }
12090
12112
  const responseContract = modelCallResponseContract(payload);
12091
- const invocation = buildExecutorInvocation(executor, command, null, { responseContract });
12092
12113
  const timeoutSeconds = Math.max(1, Math.min(
12093
12114
  config.executorTimeoutSeconds,
12094
12115
  readNumber(payload.timeoutSeconds, Math.min(config.executorTimeoutSeconds, 60))
@@ -12097,14 +12118,9 @@ async function executeModelCallCommand(config, command, signal) {
12097
12118
  config.executorMaxOutputBytes,
12098
12119
  readNumber(payload.maxOutputBytes, 512 * 1024)
12099
12120
  ));
12100
- await ackCommand(config, command, "spawned");
12101
- await ingestLog(config, command, "system", "info", `Starting ${executor.kind} runtime model call`, {
12102
- executorKind: executor.kind,
12103
- args: invocation.args,
12104
- purpose: readString(payload.purpose) ?? null,
12105
- promptBytes: Buffer.byteLength(prompt, "utf8")
12106
- });
12107
12121
  let piModelCallProfile = null;
12122
+ let modelTarget = null;
12123
+ let invocation = null;
12108
12124
  let execution;
12109
12125
  try {
12110
12126
  const baseEnv = buildExecutorEnv(config, command, {
@@ -12112,7 +12128,16 @@ async function executeModelCallCommand(config, command, signal) {
12112
12128
  cwd: process.cwd(),
12113
12129
  sourceWorkspacePath: process.cwd()
12114
12130
  });
12115
- piModelCallProfile = executor.kind === "pi" ? preparePiModelCallProfile(command.commandId, baseEnv) : null;
12131
+ const commandProvider = readString(payload.provider);
12132
+ const commandModel = readString(payload.model);
12133
+ const commandTargetRequested = Boolean(commandProvider || commandModel);
12134
+ const envProvider = readString(process.env.AMASTER_PI_PROVIDER);
12135
+ const envModel = readString(process.env.AMASTER_PI_MODEL);
12136
+ const envTargetRequested = Boolean(envProvider || envModel);
12137
+ const configuredTarget = commandTargetRequested ? { provider: commandProvider, model: commandModel, source: "command" } : { provider: envProvider, model: envModel, source: "runtime_env" };
12138
+ piModelCallProfile = executor.kind === "pi" ? preparePiModelCallProfile(command.commandId, baseEnv, {
12139
+ includeDefaults: Boolean(responseContract && !commandTargetRequested && !envTargetRequested)
12140
+ }) : null;
12116
12141
  if (piModelCallProfile) {
12117
12142
  await syncPiExecutorProviderConfig(
12118
12143
  config,
@@ -12121,16 +12146,28 @@ async function executeModelCallCommand(config, command, signal) {
12121
12146
  resolvePiExecutorProviderConfig(config, command, baseEnv)
12122
12147
  );
12123
12148
  if (responseContract) {
12124
- const provider = readString(payload.provider) ?? readString(process.env.AMASTER_PI_PROVIDER);
12125
- const model = readString(payload.model) ?? readString(process.env.AMASTER_PI_MODEL);
12149
+ modelTarget = resolvePiModelCallTarget(
12150
+ piModelCallProfile.env.PI_CODING_AGENT_DIR,
12151
+ configuredTarget.provider,
12152
+ configuredTarget.model,
12153
+ configuredTarget.source
12154
+ );
12126
12155
  applyModelCallOutputContract(
12127
12156
  piModelCallProfile.env.PI_CODING_AGENT_DIR,
12128
- provider,
12129
- model,
12157
+ modelTarget.provider,
12158
+ modelTarget.model,
12130
12159
  responseContract.maxOutputTokens
12131
12160
  );
12132
12161
  }
12133
12162
  }
12163
+ invocation = buildExecutorInvocation(executor, command, null, { responseContract, modelTarget });
12164
+ await ackCommand(config, command, "spawned");
12165
+ await ingestLog(config, command, "system", "info", `Starting ${executor.kind} runtime model call`, {
12166
+ executorKind: executor.kind,
12167
+ args: invocation.args,
12168
+ purpose: readString(payload.purpose) ?? null,
12169
+ promptBytes: Buffer.byteLength(prompt, "utf8")
12170
+ });
12134
12171
  execution = await runExecutor(invocation.command, invocation.args, {
12135
12172
  cwd: process.cwd(),
12136
12173
  env: piModelCallProfile?.env ?? baseEnv,
@@ -12173,6 +12210,11 @@ async function executeModelCallCommand(config, command, signal) {
12173
12210
  ...responseContract ? {
12174
12211
  driver: "pi_cli_json_v1",
12175
12212
  responseContract,
12213
+ ...modelTarget ? {
12214
+ provider: modelTarget.provider,
12215
+ model: modelTarget.model,
12216
+ modelTargetSource: modelTarget.source
12217
+ } : {},
12176
12218
  stopReason: parsed.stopReason ?? null,
12177
12219
  terminalEventType: parsed.terminalEventType ?? null,
12178
12220
  semanticBytes,
@@ -6,7 +6,7 @@ import { basename, dirname, join, resolve } from "node:path";
6
6
  import { homedir, hostname } from "node:os";
7
7
  import { fileURLToPath } from "node:url";
8
8
 
9
- const CONNECTOR_VERSION = "0.1.1-beta.22";
9
+ const CONNECTOR_VERSION = "0.1.1-beta.23";
10
10
 
11
11
  const CAPABILITIES = [
12
12
  "remote_registration",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amaster.ai/employee-runtime-connector",
3
- "version": "0.1.1-beta.22",
3
+ "version": "0.1.1-beta.23",
4
4
  "description": "MirrorX runtime connector CLI and daemon",
5
5
  "license": "MIT",
6
6
  "type": "module",