@tangle-network/agent-profile-materialize 1.0.1 → 1.1.0

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.
@@ -16,3 +16,5 @@ import type { HarnessId } from "./harness.js";
16
16
  export declare function keepsHarnessSystemPrompt(profile: AgentProfile | undefined, harness: HarnessId | string | undefined): boolean;
17
17
  /** Join prompt additions in order, skipping empty ones. */
18
18
  export declare function joinSystemPromptAdditions(...additions: Array<string | undefined>): string | undefined;
19
+ /** Native inline context has a bounded argument; long context belongs in resources.files. */
20
+ export declare function codexDeveloperInstructionArgs(value: string | undefined, flags?: readonly string[]): string[];
@@ -27,13 +27,12 @@ const HARNESSES_WITH_ADDITIVE_HOST_PROMPT = new Set(["claude-code", "pi", "openc
27
27
  */
28
28
  export function keepsHarnessSystemPrompt(profile, harness) {
29
29
  const prompt = profile?.prompt;
30
- if (!prompt || prompt.systemPrompt !== undefined)
30
+ if (!profile || prompt?.systemPrompt !== undefined)
31
31
  return false;
32
- const declaresIntent = (prompt.instructions?.length ?? 0) > 0 ||
33
- prompt.appendSystemPrompt !== undefined;
34
- return (declaresIntent &&
35
- harness !== undefined &&
36
- HARNESSES_WITH_ADDITIVE_HOST_PROMPT.has(harness));
32
+ return (HARNESSES_WITH_ADDITIVE_HOST_PROMPT.has(harness ?? "") &&
33
+ ((prompt?.instructions?.length ?? 0) > 0 ||
34
+ prompt?.appendSystemPrompt !== undefined ||
35
+ (harness === "codex" && profile.resources?.instructions !== undefined)));
37
36
  }
38
37
  /** Join prompt additions in order, skipping empty ones. */
39
38
  export function joinSystemPromptAdditions(...additions) {
@@ -42,3 +41,21 @@ export function joinSystemPromptAdditions(...additions) {
42
41
  .filter((addition) => Boolean(addition));
43
42
  return parts.length > 0 ? parts.join("\n\n") : undefined;
44
43
  }
44
+ /** Native inline context has a bounded argument; long context belongs in resources.files. */
45
+ export function codexDeveloperInstructionArgs(value, flags = []) {
46
+ if (value === undefined)
47
+ return [];
48
+ if (flags.some((flag, index) => {
49
+ const selector = ["-c", "--config"].includes(flags[index - 1] ?? "")
50
+ ? flag
51
+ : /^(?:--config=|-c=?)(.+)$/su.exec(flag)?.[1];
52
+ return (selector &&
53
+ /^(?:developer_instructions\s*=|["'])/u.test(selector.trimStart()));
54
+ }))
55
+ throw new Error("Codex context conflicts with a caller configuration override; put developer_instructions in the AgentProfile and use unquoted configuration keys");
56
+ const encoded = `developer_instructions=${JSON.stringify(value)}`;
57
+ // This is the adapter's portable inline budget, not an OS capacity claim.
58
+ if (Buffer.byteLength(encoded, "utf8") > 64 * 1024)
59
+ throw new Error("Codex inline context is too large; move long context into profile.resources.files and keep prompt.instructions short");
60
+ return ["-c", encoded];
61
+ }
@@ -41,6 +41,16 @@ export function hashWorkspacePlan(plan) {
41
41
  });
42
42
  return `sha256:${sha256(canonical)}`;
43
43
  }
44
+ /**
45
+ * Candidate material records prompt intents as public values only: a secret
46
+ * reference there would put credential identity into sealed evidence.
47
+ */
48
+ function publicPromptValue(value) {
49
+ if (value.kind !== "public") {
50
+ throw new Error("Candidate plan material accepts public prompt values only");
51
+ }
52
+ return { kind: "public", value: value.value };
53
+ }
44
54
  /** Build the exact digest-free identity document required by agent-interface. */
45
55
  export function agentCandidateProfilePlanMaterial(plan) {
46
56
  const files = normalizePlanFiles(plan.files);
@@ -59,7 +69,7 @@ export function agentCandidateProfilePlanMaterial(plan) {
59
69
  files: materialFiles,
60
70
  env: Object.fromEntries(Object.entries(plan.env).sort(([left], [right]) => compareStrings(left, right))),
61
71
  flags: [...plan.flags],
62
- ...promptIntentFields(plan, samePromptIntentValue),
72
+ ...promptIntentFields(plan, publicPromptValue),
63
73
  unsupported: [...plan.unsupported].sort((left, right) => compareStrings(`${left.dimension}\0${left.reason}`, `${right.dimension}\0${right.reason}`)),
64
74
  };
65
75
  const hasAgentRoot = materialFiles.some((file) => file.root === "agent");
@@ -188,15 +188,13 @@ export interface WorkspacePlan {
188
188
  */
189
189
  systemPrompt?: string;
190
190
  /**
191
- * Exact text ADDED to the harness's own system prompt, which stays intact.
191
+ * Text added to the harness context; its own system prompt stays intact.
192
192
  *
193
- * Separate from {@link WorkspacePlan.systemPrompt} because the two are
194
- * different intents against the same channel, and every harness that has one
195
- * control may lack the other. An executor binds this ONLY to an additive
196
- * control (claude-code `--append-system-prompt`, pi
197
- * `--append-system-prompt`); there is no harness for which folding it into
198
- * the replacement is correct, because that would delete the built-in prompt
199
- * the caller asked to keep.
193
+ * Claude Code and Pi bind their additive system-prompt control. Codex binds
194
+ * ordinary profile instructions to developer_instructions, composed once
195
+ * with host context; this is not a privileged system-prompt append. Authored
196
+ * Codex appendSystemPrompt remains unsupported. Never fold this into an exact
197
+ * system-prompt replacement, which carries the caller's unchanged bytes.
200
198
  */
201
199
  appendSystemPrompt?: string;
202
200
  /**
@@ -70,10 +70,7 @@ export function lowerProfilePrompt(profile, harness, binds, instructionsRoot, bu
70
70
  unsupported("appendSystemPrompt", appendSystemPromptRefusal(harness));
71
71
  }
72
72
  }
73
- const instructions = [];
74
- if (profile.prompt?.instructions?.length) {
75
- instructions.push(...profile.prompt.instructions);
76
- }
73
+ const instructions = [...(profile.prompt?.instructions ?? [])];
77
74
  const resourceInstructions = profile.resources?.instructions;
78
75
  if (typeof resourceInstructions === "string") {
79
76
  instructions.push(resourceInstructions);
@@ -85,7 +82,12 @@ export function lowerProfilePrompt(profile, harness, binds, instructionsRoot, bu
85
82
  unsupported("instructions", "instruction ref is not inline (github refs need async pre-resolution)");
86
83
  }
87
84
  if (instructions.length) {
88
- if (openCodeConfigUnreachable) {
85
+ if (harness === "codex") {
86
+ // Codex's developer channel composes profile context without replacing
87
+ // repository AGENTS.md or the harness's own system instructions.
88
+ plan.appendSystemPrompt = instructions.join("\n\n");
89
+ }
90
+ else if (openCodeConfigUnreachable) {
89
91
  unsupported("instructions", "opencode: the launcher that binds opencode.agent-prompt composes opencode's config itself and loads no workspace opencode.json, so an instruction file registered there would never reach the model; compose it into the launcher's own instructions[]");
90
92
  }
91
93
  else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/agent-profile-materialize",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "description": "Materialize an AgentProfile into the native per-harness workspace files (the one shared materializer for cli-bridge, agent-container, and VB).",
5
5
  "type": "module",
6
6
  "repository": {
@@ -25,8 +25,8 @@
25
25
  "dist"
26
26
  ],
27
27
  "devDependencies": {
28
- "@tangle-network/agent-interface": "5.0.0",
29
- "@tangle-network/agent-interface-current": "npm:@tangle-network/agent-interface@5.0.0",
28
+ "@tangle-network/agent-interface": "5.8.1",
29
+ "@tangle-network/agent-interface-current": "npm:@tangle-network/agent-interface@5.8.1",
30
30
  "@types/node": "25.6.0",
31
31
  "typescript": "^6.0.3",
32
32
  "vitest": "^4.1.12"
@@ -35,8 +35,8 @@
35
35
  "@tangle-network/agent-interface": "^3.0.0 || ^4.0.0 || ^5.0.0"
36
36
  },
37
37
  "tangleRelease": {
38
- "sourceSha": "ee7221645e1dd25f4bc3ebe69286b336ce92eda2",
39
- "mergedAt": "2026-10-27T01:07:43-06:00"
38
+ "sourceSha": "ce60ebd2e2bcf72a575754bc886f82e3b843c192",
39
+ "mergedAt": "2026-10-27T04:52:24-06:00"
40
40
  },
41
41
  "scripts": {
42
42
  "build": "tsc -p tsconfig.json",