@xfey/tutti 0.1.106 → 0.1.108
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/collaboration-ingestion/external-source.js +10 -1
- package/dist/control-plane/procedure-logging.d.ts +1 -0
- package/dist/control-plane/procedure-logging.js +16 -5
- package/dist/control-plane/reference-summary-refresh.js +2 -2
- package/dist/control-plane/task-source-context-types.d.ts +2 -1
- package/dist/control-plane/task-source-context.js +7 -0
- package/dist/control-plane/workflows/openai.js +1 -0
- package/dist/providers/openai/app-server/read-only-procedure.d.ts +10 -2
- package/dist/providers/openai/app-server/read-only-procedure.js +68 -15
- package/dist/providers/openai/app-server/skills.d.ts +4 -1
- package/dist/providers/openai/app-server/skills.js +12 -2
- package/dist/providers/openai/app-server/workspace-write-run.js +14 -10
- package/dist/reference-access/cache.d.ts +50 -0
- package/dist/reference-access/cache.js +268 -0
- package/dist/reference-access/read-evidence.d.ts +6 -0
- package/dist/reference-access/read-evidence.js +15 -0
- package/dist/reference-access/service.d.ts +26 -0
- package/dist/reference-access/service.js +42 -0
- package/dist/server-shell/cli/external-reference-runtime.d.ts +12 -0
- package/dist/server-shell/cli/external-reference-runtime.js +75 -0
- package/dist/server-shell/cli/host-server-runtime.js +17 -1
- package/dist/server-shell/cli/relay-registration.js +1 -0
- package/dist/server-shell/http/create-server.d.ts +2 -0
- package/dist/server-shell/http/create-server.js +5 -4
- package/dist/server-shell/http/routes/agent-context-auth.d.ts +2 -1
- package/dist/server-shell/http/routes/agent-context-auth.js +3 -1
- package/dist/server-shell/http/routes/agent-context-external-reference-routes.d.ts +4 -0
- package/dist/server-shell/http/routes/agent-context-external-reference-routes.js +83 -0
- package/dist/server-shell/http/routes/agent-context-shared.d.ts +2 -0
- package/dist/server-shell/http/routes/agent-context.js +3 -1
- package/dist/server-shell/http/routes/project-api/reference-files-routes.js +19 -2
- package/dist/workspace-ops/project-workspace.js +6 -6
- package/dist/workspace-ops/reference-cache-policy.d.ts +6 -0
- package/dist/workspace-ops/reference-cache-policy.js +79 -0
- package/migrations/0021_external_reference_reads.sql +11 -0
- package/node_modules/@tutti/relay-client/dist/external-references.d.ts +11 -0
- package/node_modules/@tutti/relay-client/dist/external-references.js +63 -0
- package/node_modules/@tutti/relay-client/dist/host-control.d.ts +1 -0
- package/node_modules/@tutti/relay-client/dist/host-control.js +1 -0
- package/node_modules/@tutti/relay-client/dist/index.d.ts +1 -0
- package/node_modules/@tutti/relay-client/dist/index.js +1 -0
- package/node_modules/@tutti/shared/dist/schemas/api/clarifications.d.ts +6 -0
- package/node_modules/@tutti/shared/dist/schemas/api/external-references.d.ts +23 -0
- package/node_modules/@tutti/shared/dist/schemas/api/external-references.js +21 -0
- package/node_modules/@tutti/shared/dist/schemas/api/feishu-documents.d.ts +46 -0
- package/node_modules/@tutti/shared/dist/schemas/api/feishu-documents.js +53 -0
- package/node_modules/@tutti/shared/dist/schemas/api/index.d.ts +4 -2
- package/node_modules/@tutti/shared/dist/schemas/api/index.js +3 -1
- package/node_modules/@tutti/shared/dist/schemas/api/messages.d.ts +24 -0
- package/node_modules/@tutti/shared/dist/schemas/api/messages.js +2 -0
- package/node_modules/@tutti/shared/dist/schemas/api/platform-sessions.d.ts +10 -1
- package/node_modules/@tutti/shared/dist/schemas/api/platform-sessions.js +23 -1
- package/node_modules/@tutti/shared/dist/schemas/api/viewer-reference.d.ts +6 -0
- package/node_modules/@tutti/shared/dist/schemas/internal/external-references.d.ts +109 -0
- package/node_modules/@tutti/shared/dist/schemas/internal/external-references.js +70 -0
- package/node_modules/@tutti/shared/dist/schemas/internal/feishu-documents.d.ts +49 -0
- package/node_modules/@tutti/shared/dist/schemas/internal/feishu-documents.js +36 -0
- package/node_modules/@tutti/shared/dist/schemas/internal/index.d.ts +2 -0
- package/node_modules/@tutti/shared/dist/schemas/internal/index.js +2 -0
- package/node_modules/@tutti/shared/dist/schemas/internal/platform-integration.d.ts +36 -0
- package/node_modules/@tutti/shared/dist/schemas/internal/platform-integration.js +3 -0
- package/package.json +1 -1
- package/prompts/skills/read-references/SKILL.md +32 -3
- package/web/assets/{homepage-motion-scene-tfFEdV9Y.js → homepage-motion-scene-B6yPJnY8.js} +1 -1
- package/web/assets/{index-C2Mmj25S.css → index-DvfZ57Nl.css} +1 -1
- package/web/assets/index-aQnJ5JoI.js +69 -0
- package/web/index.html +2 -2
- package/web/assets/index-B7ZGIvOv.js +0 -69
package/README.md
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
- host 到 Relay 的连接与工作区加入协作
|
|
16
16
|
- machine-local `standalone | feishu` Project Surface authority,以及Standalone browser session / Feishu trusted integration的双向Host gate
|
|
17
17
|
- Feishu主群聊Chat Assistant canonical response与Host-owned durable outbound handoff intent
|
|
18
|
+
- Feishu 外部来源的按需读取、受控临时 cache、invocation 版本和 SQLite 读取证据;正式 Reference/Standalone 上传与历史 snapshot 保持,见 [external-reference-access.md](../../docs/system/external-reference-access.md)
|
|
18
19
|
|
|
19
20
|
## 结构
|
|
20
21
|
|
|
@@ -26,6 +27,7 @@
|
|
|
26
27
|
- `prepare-package-assets.mjs`:把 Web build output 和内部 runtime package 复制到 staging package 所需位置。
|
|
27
28
|
- `pack-dry-run.mjs`:构建 staging package 并执行 `npm pack --dry-run --json` 文件列表校验。
|
|
28
29
|
- `smoke-packed-cli.mjs`:安装并验证 packed CLI tarball 的本地 smoke,包括 CLI help / version、runtime deps 和 QR dependency。
|
|
30
|
+
- 发布时可将 `TUTTI_PACKED_CLI_ARTIFACT_DIR` 指向已存在的独立绝对目录;仅全部 smoke 成功后保留同一已测 `.tgz`,拒绝覆盖同名文件,输出 SHA-256 而不输出临时路径。默认仍清理临时产物。
|
|
29
31
|
- `smoke-desktop-protocol.mjs`:在真实 `~/Applications` 下使用唯一临时 bundle / scheme 验证 macOS 图标点击与 LaunchServices URL event,并在结束时注销、清理。
|
|
30
32
|
- `vitest.config.mjs`:默认快速 Server 测试入口,排除真实 Git、子进程、loopback Host 与 npm preview 集成套件。
|
|
31
33
|
- `vitest.integration.config.mjs`:显式 Server integration 入口;完整保留上述慢套件的行为覆盖。
|
|
@@ -86,7 +86,13 @@ export function ingestTrustedConversationSource(options) {
|
|
|
86
86
|
account_ref: options.command.actor.account_ref,
|
|
87
87
|
display_name: options.command.actor.display_name,
|
|
88
88
|
},
|
|
89
|
-
materialize: () => ({
|
|
89
|
+
materialize: () => ({
|
|
90
|
+
kind: "message",
|
|
91
|
+
body: source.content.text,
|
|
92
|
+
...(source.external_references === undefined
|
|
93
|
+
? {}
|
|
94
|
+
: { refs: { external_references: source.external_references } }),
|
|
95
|
+
}),
|
|
90
96
|
idempotencyContext: {
|
|
91
97
|
kind: "external_conversation_source",
|
|
92
98
|
platform: source.locator.conversation.installation.platform,
|
|
@@ -94,6 +100,9 @@ export function ingestTrustedConversationSource(options) {
|
|
|
94
100
|
external_message_ref: source.locator.message_ref,
|
|
95
101
|
binding_ref: options.command.binding_ref,
|
|
96
102
|
receipt_key: options.command.receipt.receipt_key,
|
|
103
|
+
...(source.external_references === undefined
|
|
104
|
+
? {}
|
|
105
|
+
: { external_references: source.external_references }),
|
|
97
106
|
},
|
|
98
107
|
afterCreate: (tx, message) => insertExternalSourceEvidence(tx, options.command, message),
|
|
99
108
|
...(options.scratchpadSource === undefined
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ActivityRef, WorkflowInvocationRef } from "@tutti/shared/ids";
|
|
2
2
|
import type { WorkflowKind } from "@tutti/shared/domain";
|
|
3
3
|
import type { ControlPlaneLogger } from "./types.js";
|
|
4
|
+
export declare function procedureExecutionErrorFields(error: unknown): Record<string, unknown>;
|
|
4
5
|
export declare function logProcedureExecutionError(input: {
|
|
5
6
|
logger: ControlPlaneLogger | undefined;
|
|
6
7
|
workflowKind: WorkflowKind;
|
|
@@ -8,6 +8,12 @@ const SAFE_DETAIL_KEYS = [
|
|
|
8
8
|
"notification_count",
|
|
9
9
|
"server_request_methods",
|
|
10
10
|
"notification_methods",
|
|
11
|
+
"output_parse_reason",
|
|
12
|
+
"agent_output_chars",
|
|
13
|
+
"json_candidate_count",
|
|
14
|
+
"agent_message_count",
|
|
15
|
+
"completed_tool_count",
|
|
16
|
+
"file_tool_count",
|
|
11
17
|
];
|
|
12
18
|
function isRecord(value) {
|
|
13
19
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -37,16 +43,21 @@ function errorCode(error) {
|
|
|
37
43
|
}
|
|
38
44
|
return error.code;
|
|
39
45
|
}
|
|
46
|
+
export function procedureExecutionErrorFields(error) {
|
|
47
|
+
const code = errorCode(error);
|
|
48
|
+
const details = errorDetails(error);
|
|
49
|
+
return {
|
|
50
|
+
error_name: error instanceof Error ? error.name : "NonError",
|
|
51
|
+
...(code === undefined ? {} : { error_code: code }),
|
|
52
|
+
...(details === undefined ? {} : { error_details: details }),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
40
55
|
export function logProcedureExecutionError(input) {
|
|
41
56
|
input.logger?.info({
|
|
42
57
|
activity_ref: input.activityRef,
|
|
43
58
|
workflow_ref: input.workflowRef,
|
|
44
59
|
workflow_kind: input.workflowKind,
|
|
45
|
-
|
|
46
|
-
...(errorCode(input.error) === undefined ? {} : { error_code: errorCode(input.error) }),
|
|
47
|
-
...(errorDetails(input.error) === undefined
|
|
48
|
-
? {}
|
|
49
|
-
: { error_details: errorDetails(input.error) }),
|
|
60
|
+
...procedureExecutionErrorFields(input.error),
|
|
50
61
|
}, "Procedure execution error");
|
|
51
62
|
}
|
|
52
63
|
//# sourceMappingURL=procedure-logging.js.map
|
|
@@ -2,7 +2,7 @@ import { createWorkflowInvocationRef } from "@tutti/shared/ids";
|
|
|
2
2
|
import { recordProjectTimelineEvent } from "../project-timeline/index.js";
|
|
3
3
|
import { withHostStoreTransaction } from "../store/index.js";
|
|
4
4
|
import { WorkspaceOpsError, readReferenceSummaryTargets, updateReferenceSummaries, } from "../workspace-ops/index.js";
|
|
5
|
-
import { logProcedureExecutionError } from "./procedure-logging.js";
|
|
5
|
+
import { logProcedureExecutionError, procedureExecutionErrorFields } from "./procedure-logging.js";
|
|
6
6
|
import { enqueueControlPlaneIntent, readControlPlaneIntentByDedupeKey, settlePendingControlPlaneIntent, } from "./dispatch-intents.js";
|
|
7
7
|
const REFERENCE_SUMMARY_CONCURRENCY = 1;
|
|
8
8
|
const REFERENCE_SUMMARY_MAX_ATTEMPTS = 2;
|
|
@@ -255,7 +255,7 @@ async function summarizeReferenceTarget(options) {
|
|
|
255
255
|
path: options.target.path,
|
|
256
256
|
attempt,
|
|
257
257
|
retrying: attempt < REFERENCE_SUMMARY_MAX_ATTEMPTS,
|
|
258
|
-
|
|
258
|
+
...procedureExecutionErrorFields(error),
|
|
259
259
|
}, attempt < REFERENCE_SUMMARY_MAX_ATTEMPTS
|
|
260
260
|
? "Reference summary target retrying"
|
|
261
261
|
: "Reference summary target failed");
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import type { ClarificationRequestPayload } from "@tutti/shared/schemas/api";
|
|
1
|
+
import type { ClarificationRequestPayload, ExternalReferenceDescriptor } from "@tutti/shared/schemas/api";
|
|
2
2
|
export type PromptSourceMessage = {
|
|
3
3
|
role: "human" | "tutti";
|
|
4
4
|
author_display_name?: string;
|
|
5
5
|
text: string;
|
|
6
|
+
external_references?: ExternalReferenceDescriptor[];
|
|
6
7
|
};
|
|
7
8
|
export type TaskCompileClarificationContext = {
|
|
8
9
|
request_payload: ClarificationRequestPayload;
|
|
@@ -16,6 +16,13 @@ function promptSourceMessage(db, source) {
|
|
|
16
16
|
? {}
|
|
17
17
|
: { author_display_name: displayName }),
|
|
18
18
|
text: messageTextForModel(message),
|
|
19
|
+
...(message.refs?.external_references === undefined
|
|
20
|
+
? {}
|
|
21
|
+
: {
|
|
22
|
+
external_references: message.refs.external_references.map((reference) => ({
|
|
23
|
+
...reference,
|
|
24
|
+
})),
|
|
25
|
+
}),
|
|
19
26
|
};
|
|
20
27
|
}
|
|
21
28
|
if (message.message_kind === "agent_text" && message.author.kind === "agent") {
|
|
@@ -447,6 +447,7 @@ export function createOpenAiProcedureWorkflowRunner(options) {
|
|
|
447
447
|
appServerCwd: workspace.cwd,
|
|
448
448
|
validateOutput: isReferenceFileSummaryStructuredOutput,
|
|
449
449
|
readablePaths: [workspace.cwd],
|
|
450
|
+
requireFileToolUse: true,
|
|
450
451
|
networkAccess: false,
|
|
451
452
|
webSearchMode: "disabled",
|
|
452
453
|
});
|
|
@@ -11,6 +11,8 @@ export type CodexAppServerReadOnlyProcedureInput<TOutput> = {
|
|
|
11
11
|
workspaceRoot: string;
|
|
12
12
|
appServerCwd?: string;
|
|
13
13
|
readablePaths?: string[];
|
|
14
|
+
/** File-only workflows must not accept an answer produced without a filesystem tool attempt. */
|
|
15
|
+
requireFileToolUse?: boolean;
|
|
14
16
|
prompt: string;
|
|
15
17
|
outputSchema: unknown;
|
|
16
18
|
validateOutput: (value: unknown) => value is TOutput;
|
|
@@ -66,11 +68,17 @@ export type CodexAppServerReadOnlyProcedureErrorDetails = {
|
|
|
66
68
|
notification_methods?: string[];
|
|
67
69
|
agent_message_excerpt?: string;
|
|
68
70
|
stderr_excerpt?: string;
|
|
71
|
+
output_parse_reason?: "no_json_object" | "malformed_json";
|
|
72
|
+
agent_output_chars?: number;
|
|
73
|
+
json_candidate_count?: number;
|
|
74
|
+
agent_message_count?: number;
|
|
75
|
+
completed_tool_count?: number;
|
|
76
|
+
file_tool_count?: number;
|
|
69
77
|
};
|
|
70
78
|
export declare class CodexAppServerReadOnlyProcedureError extends Error {
|
|
71
|
-
readonly code: "app_server_protocol_error" | "auth_failed" | "thread_start_failed" | "turn_failed" | "turn_timeout" | "unexpected_server_request" | "skill_selection_failed" | "output_parse_failed" | "output_validation_failed" | "write_detected" | "secret_leak_detected" | "process_lifecycle_failed" | "admission_unavailable";
|
|
79
|
+
readonly code: "app_server_protocol_error" | "auth_failed" | "thread_start_failed" | "turn_failed" | "turn_timeout" | "unexpected_server_request" | "skill_selection_failed" | "output_parse_failed" | "output_validation_failed" | "file_read_not_observed" | "write_detected" | "secret_leak_detected" | "process_lifecycle_failed" | "admission_unavailable";
|
|
72
80
|
readonly details: CodexAppServerReadOnlyProcedureErrorDetails;
|
|
73
|
-
constructor(code: "app_server_protocol_error" | "auth_failed" | "thread_start_failed" | "turn_failed" | "turn_timeout" | "unexpected_server_request" | "skill_selection_failed" | "output_parse_failed" | "output_validation_failed" | "write_detected" | "secret_leak_detected" | "process_lifecycle_failed" | "admission_unavailable", message: string, details?: CodexAppServerReadOnlyProcedureErrorDetails);
|
|
81
|
+
constructor(code: "app_server_protocol_error" | "auth_failed" | "thread_start_failed" | "turn_failed" | "turn_timeout" | "unexpected_server_request" | "skill_selection_failed" | "output_parse_failed" | "output_validation_failed" | "file_read_not_observed" | "write_detected" | "secret_leak_detected" | "process_lifecycle_failed" | "admission_unavailable", message: string, details?: CodexAppServerReadOnlyProcedureErrorDetails);
|
|
74
82
|
}
|
|
75
83
|
export declare function resolveReadOnlyWebSearchMode(input: {
|
|
76
84
|
networkAccess?: boolean;
|
|
@@ -4,14 +4,14 @@ import { tmpdir } from "node:os";
|
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { buildCodexAppServerProcessPlan } from "../codex-app-server.js";
|
|
6
6
|
import { DEFAULT_OPENAI_MODEL } from "../model-config.js";
|
|
7
|
-
import { CodexAppServerJsonRpcClient, CodexAppServerProtocolError
|
|
7
|
+
import { CodexAppServerJsonRpcClient, CodexAppServerProtocolError } from "./json-rpc.js";
|
|
8
8
|
import { CodexAppServerInvocation, CodexAppServerLifecycleError, createManagedProcess, } from "./invocation-lifecycle.js";
|
|
9
9
|
import { CodexAppServerAdmissionError, } from "./invocation-coordinator.js";
|
|
10
10
|
import { createCodexAppServerRuntimeObserver, } from "./runtime-telemetry.js";
|
|
11
11
|
import { createReadOnlySandboxPolicy } from "./sandbox-policy.js";
|
|
12
12
|
import { buildCodexAppServerProviderConfigOverrides, resolveCodexAppServerModelProvider, } from "./provider-config.js";
|
|
13
13
|
import { buildCodexAppServerTurnInput, resolveCodexAppServerContextRuntimeHint, resolveCodexAppServerSkillInputs, CodexAppServerSkillSelectionError, } from "./skills.js";
|
|
14
|
-
import { containsKnownSecret, createCodexSpawnEnv, extractAgentText, extractServerRequestMethod, findJsonObjectCandidates, isApiKeyAccount, readThreadId, readTurnError, readTurnStatus, redactWithKnownValues, compactText, } from "./runtime-helpers.js";
|
|
14
|
+
import { containsKnownSecret, createCodexSpawnEnv, extractAgentText, extractServerRequestMethod, findJsonObjectCandidates, isRecord, isApiKeyAccount, readThreadId, readTurnError, readTurnStatus, redactWithKnownValues, compactText, } from "./runtime-helpers.js";
|
|
15
15
|
import { extractCodexAppServerTokenUsage } from "../token-usage.js";
|
|
16
16
|
const DEFAULT_REQUEST_TIMEOUT_MS = 60_000;
|
|
17
17
|
const DEFAULT_TURN_TIMEOUT_MS = 600_000;
|
|
@@ -65,7 +65,11 @@ function readOnlyTimeoutDetails(input) {
|
|
|
65
65
|
export function parseCodexAppServerStructuredJson(text) {
|
|
66
66
|
const candidates = findJsonObjectCandidates(text);
|
|
67
67
|
if (candidates.length === 0) {
|
|
68
|
-
throw new CodexAppServerReadOnlyProcedureError("output_parse_failed", "Codex app-server did not return a JSON object."
|
|
68
|
+
throw new CodexAppServerReadOnlyProcedureError("output_parse_failed", "Codex app-server did not return a JSON object.", {
|
|
69
|
+
output_parse_reason: "no_json_object",
|
|
70
|
+
agent_output_chars: text.length,
|
|
71
|
+
json_candidate_count: 0,
|
|
72
|
+
});
|
|
69
73
|
}
|
|
70
74
|
for (const jsonText of candidates.toReversed()) {
|
|
71
75
|
try {
|
|
@@ -75,7 +79,37 @@ export function parseCodexAppServerStructuredJson(text) {
|
|
|
75
79
|
// Earlier app-server progress can contain brace-shaped text.
|
|
76
80
|
}
|
|
77
81
|
}
|
|
78
|
-
throw new CodexAppServerReadOnlyProcedureError("output_parse_failed", "Codex app-server returned malformed JSON."
|
|
82
|
+
throw new CodexAppServerReadOnlyProcedureError("output_parse_failed", "Codex app-server returned malformed JSON.", {
|
|
83
|
+
output_parse_reason: "malformed_json",
|
|
84
|
+
agent_output_chars: text.length,
|
|
85
|
+
json_candidate_count: candidates.length,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
/** Counts only; model text, tool arguments and stderr never enter structured diagnostics. */
|
|
89
|
+
function structuredOutputDetails(client, text) {
|
|
90
|
+
const itemTypes = client.notifications.flatMap((notification) => {
|
|
91
|
+
const params = notification.params;
|
|
92
|
+
return notification.method === "item/completed" &&
|
|
93
|
+
isRecord(params) &&
|
|
94
|
+
isRecord(params.item) &&
|
|
95
|
+
typeof params.item.type === "string"
|
|
96
|
+
? [params.item.type]
|
|
97
|
+
: [];
|
|
98
|
+
});
|
|
99
|
+
return {
|
|
100
|
+
turn_status: "completed",
|
|
101
|
+
notification_count: client.notifications.length,
|
|
102
|
+
notification_methods: client.notifications
|
|
103
|
+
.map((notification) => notification.method)
|
|
104
|
+
.slice(-20),
|
|
105
|
+
server_request_methods: client.serverRequests.map(extractServerRequestMethod),
|
|
106
|
+
agent_output_chars: text.length,
|
|
107
|
+
json_candidate_count: findJsonObjectCandidates(text).length,
|
|
108
|
+
agent_message_count: itemTypes.filter((type) => type === "agentMessage").length,
|
|
109
|
+
completed_tool_count: itemTypes.filter((type) => ["commandExecution", "mcpToolCall", "dynamicToolCall", "imageView", "webSearch"].includes(type)).length,
|
|
110
|
+
file_tool_count: itemTypes.filter((type) => ["commandExecution", "imageView"].includes(type))
|
|
111
|
+
.length,
|
|
112
|
+
};
|
|
79
113
|
}
|
|
80
114
|
export async function runCodexAppServerReadOnlyProcedure(options) {
|
|
81
115
|
if (options.invocationCoordinator !== undefined && options.invocationLease === undefined) {
|
|
@@ -102,14 +136,21 @@ export async function runCodexAppServerReadOnlyProcedure(options) {
|
|
|
102
136
|
let contextRuntimeHint;
|
|
103
137
|
try {
|
|
104
138
|
skillInputs = resolveCodexAppServerSkillInputs({
|
|
105
|
-
...(options.skillSelectionName === undefined
|
|
139
|
+
...(options.skillSelectionName === undefined
|
|
140
|
+
? {}
|
|
141
|
+
: { selectionName: options.skillSelectionName }),
|
|
106
142
|
...(options.userSkillsRoot === undefined ? {} : { userSkillsRoot: options.userSkillsRoot }),
|
|
107
143
|
...(options.builtInSkillsRoot === undefined
|
|
108
144
|
? {}
|
|
109
145
|
: { builtInSkillsRoot: options.builtInSkillsRoot }),
|
|
110
146
|
});
|
|
111
147
|
contextRuntimeHint = resolveCodexAppServerContextRuntimeHint({
|
|
112
|
-
...(options.
|
|
148
|
+
...(options.runtimeTelemetry?.activityRef === undefined
|
|
149
|
+
? {}
|
|
150
|
+
: { activityRef: options.runtimeTelemetry.activityRef }),
|
|
151
|
+
...(options.skillSelectionName === undefined
|
|
152
|
+
? {}
|
|
153
|
+
: { selectionName: options.skillSelectionName }),
|
|
113
154
|
...(options.agentContext === undefined ? {} : { agentContext: options.agentContext }),
|
|
114
155
|
});
|
|
115
156
|
}
|
|
@@ -184,10 +225,7 @@ export async function runCodexAppServerReadOnlyProcedure(options) {
|
|
|
184
225
|
...(contextRuntimeHint?.sensitiveValues ?? []),
|
|
185
226
|
...skillInputs.map((skill) => skill.path),
|
|
186
227
|
];
|
|
187
|
-
const strictLeakCheckValues = [
|
|
188
|
-
options.apiKey,
|
|
189
|
-
...(contextRuntimeHint?.sensitiveValues ?? []),
|
|
190
|
-
];
|
|
228
|
+
const strictLeakCheckValues = [options.apiKey, ...(contextRuntimeHint?.sensitiveValues ?? [])];
|
|
191
229
|
let primaryError;
|
|
192
230
|
let procedureResult;
|
|
193
231
|
let lifecycleError;
|
|
@@ -249,9 +287,7 @@ export async function runCodexAppServerReadOnlyProcedure(options) {
|
|
|
249
287
|
input: buildCodexAppServerTurnInput({
|
|
250
288
|
prompt: options.prompt,
|
|
251
289
|
skills: skillInputs,
|
|
252
|
-
...(contextRuntimeHint === undefined
|
|
253
|
-
? {}
|
|
254
|
-
: { runtimeHints: [contextRuntimeHint.text] }),
|
|
290
|
+
...(contextRuntimeHint === undefined ? {} : { runtimeHints: [contextRuntimeHint.text] }),
|
|
255
291
|
}),
|
|
256
292
|
cwd: appServerCwd,
|
|
257
293
|
approvalPolicy: "never",
|
|
@@ -314,9 +350,26 @@ export async function runCodexAppServerReadOnlyProcedure(options) {
|
|
|
314
350
|
const agentText = client.notifications
|
|
315
351
|
.map((notification) => extractAgentText(notification))
|
|
316
352
|
.join("");
|
|
317
|
-
|
|
353
|
+
let parsed;
|
|
354
|
+
try {
|
|
355
|
+
parsed = parseCodexAppServerStructuredJson(agentText);
|
|
356
|
+
}
|
|
357
|
+
catch (error) {
|
|
358
|
+
if (!(error instanceof CodexAppServerReadOnlyProcedureError))
|
|
359
|
+
throw error;
|
|
360
|
+
throw new CodexAppServerReadOnlyProcedureError(error.code, error.message, {
|
|
361
|
+
...structuredOutputDetails(client, agentText),
|
|
362
|
+
...error.details,
|
|
363
|
+
});
|
|
364
|
+
}
|
|
318
365
|
if (!options.validateOutput(parsed)) {
|
|
319
|
-
throw new CodexAppServerReadOnlyProcedureError("output_validation_failed", "Codex app-server structured output did not match the expected schema.");
|
|
366
|
+
throw new CodexAppServerReadOnlyProcedureError("output_validation_failed", "Codex app-server structured output did not match the expected schema.", structuredOutputDetails(client, agentText));
|
|
367
|
+
}
|
|
368
|
+
if (options.requireFileToolUse === true) {
|
|
369
|
+
const details = structuredOutputDetails(client, agentText);
|
|
370
|
+
if (details.file_tool_count === 0) {
|
|
371
|
+
throw new CodexAppServerReadOnlyProcedureError("file_read_not_observed", "Codex app-server did not attempt to inspect the summary source file.", details);
|
|
372
|
+
}
|
|
320
373
|
}
|
|
321
374
|
const gitStatusAfter = readGitStatus(options.workspaceRoot);
|
|
322
375
|
if (gitStatusAfter !== gitStatusBefore) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ActivityRef } from "@tutti/shared/ids";
|
|
1
2
|
export type CodexAppServerSkillInput = {
|
|
2
3
|
name: string;
|
|
3
4
|
path: string;
|
|
@@ -15,13 +16,14 @@ export type CodexAppServerSkillInputItem = {
|
|
|
15
16
|
export type CodexAppServerTurnInputItem = CodexAppServerSkillInputItem | CodexAppServerTextInputItem;
|
|
16
17
|
export type CodexAppServerBuiltInSkillName = "read-main-chat" | "read-project-docs" | "read-scratchpad" | "read-worklist" | "read-references" | "read-user-skills";
|
|
17
18
|
export type CodexAppServerSkillSelectionName = "chat_assistant" | "project_context_bootstrap" | "task_compile" | "context_sync" | "reference_summary_refresh" | "workspace_write_run" | "follow_up_run";
|
|
18
|
-
export type CodexAppServerContextApiScope = "messages:read" | "project-docs:list" | "project-docs:read" | "scratchpad:read" | "worklist:read" | "task:read" | "references:list" | "references:read" | "skills:list" | "skills:read";
|
|
19
|
+
export type CodexAppServerContextApiScope = "messages:read" | "project-docs:list" | "project-docs:read" | "scratchpad:read" | "worklist:read" | "task:read" | "references:list" | "references:read" | "references:external" | "skills:list" | "skills:read";
|
|
19
20
|
export type CodexAppServerSkillSelection = {
|
|
20
21
|
builtInSkillNames: CodexAppServerBuiltInSkillName[];
|
|
21
22
|
userSkillMode: "disabled" | "all_enabled";
|
|
22
23
|
contextApiScopes: CodexAppServerContextApiScope[];
|
|
23
24
|
};
|
|
24
25
|
export type CodexAppServerAgentContextTokenRequest = {
|
|
26
|
+
activityRef?: ActivityRef;
|
|
25
27
|
selectionName: CodexAppServerSkillSelectionName;
|
|
26
28
|
scopes: CodexAppServerContextApiScope[];
|
|
27
29
|
};
|
|
@@ -76,6 +78,7 @@ export declare function buildCodexAppServerContextRuntimeHint(options: {
|
|
|
76
78
|
expiresAt?: string;
|
|
77
79
|
}): string;
|
|
78
80
|
export declare function resolveCodexAppServerContextRuntimeHint(options: {
|
|
81
|
+
activityRef?: ActivityRef;
|
|
79
82
|
selectionName?: CodexAppServerSkillSelectionName;
|
|
80
83
|
agentContext?: CodexAppServerAgentContextRuntime;
|
|
81
84
|
}): CodexAppServerContextRuntimeHint | undefined;
|
|
@@ -30,6 +30,7 @@ export const CODEX_APP_SERVER_SKILL_SELECTIONS = {
|
|
|
30
30
|
"task:read",
|
|
31
31
|
"references:list",
|
|
32
32
|
"references:read",
|
|
33
|
+
"references:external",
|
|
33
34
|
"skills:list",
|
|
34
35
|
"skills:read",
|
|
35
36
|
],
|
|
@@ -42,6 +43,7 @@ export const CODEX_APP_SERVER_SKILL_SELECTIONS = {
|
|
|
42
43
|
"project-docs:read",
|
|
43
44
|
"references:list",
|
|
44
45
|
"references:read",
|
|
46
|
+
"references:external",
|
|
45
47
|
],
|
|
46
48
|
},
|
|
47
49
|
task_compile: {
|
|
@@ -54,6 +56,7 @@ export const CODEX_APP_SERVER_SKILL_SELECTIONS = {
|
|
|
54
56
|
"task:read",
|
|
55
57
|
"references:list",
|
|
56
58
|
"references:read",
|
|
59
|
+
"references:external",
|
|
57
60
|
],
|
|
58
61
|
},
|
|
59
62
|
context_sync: {
|
|
@@ -74,23 +77,29 @@ export const CODEX_APP_SERVER_SKILL_SELECTIONS = {
|
|
|
74
77
|
contextApiScopes: [],
|
|
75
78
|
},
|
|
76
79
|
workspace_write_run: {
|
|
77
|
-
builtInSkillNames: ["read-project-docs", "read-worklist"],
|
|
80
|
+
builtInSkillNames: ["read-project-docs", "read-worklist", "read-references"],
|
|
78
81
|
userSkillMode: "all_enabled",
|
|
79
82
|
contextApiScopes: [
|
|
80
83
|
"project-docs:list",
|
|
81
84
|
"project-docs:read",
|
|
82
85
|
"worklist:read",
|
|
83
86
|
"task:read",
|
|
87
|
+
"references:list",
|
|
88
|
+
"references:read",
|
|
89
|
+
"references:external",
|
|
84
90
|
],
|
|
85
91
|
},
|
|
86
92
|
follow_up_run: {
|
|
87
|
-
builtInSkillNames: ["read-project-docs", "read-worklist"],
|
|
93
|
+
builtInSkillNames: ["read-project-docs", "read-worklist", "read-references"],
|
|
88
94
|
userSkillMode: "all_enabled",
|
|
89
95
|
contextApiScopes: [
|
|
90
96
|
"project-docs:list",
|
|
91
97
|
"project-docs:read",
|
|
92
98
|
"worklist:read",
|
|
93
99
|
"task:read",
|
|
100
|
+
"references:list",
|
|
101
|
+
"references:read",
|
|
102
|
+
"references:external",
|
|
94
103
|
],
|
|
95
104
|
},
|
|
96
105
|
};
|
|
@@ -206,6 +215,7 @@ export function resolveCodexAppServerContextRuntimeHint(options) {
|
|
|
206
215
|
return undefined;
|
|
207
216
|
}
|
|
208
217
|
const issued = options.agentContext.issueToken({
|
|
218
|
+
...(options.activityRef === undefined ? {} : { activityRef: options.activityRef }),
|
|
209
219
|
selectionName: options.selectionName,
|
|
210
220
|
scopes: selection.contextApiScopes,
|
|
211
221
|
});
|
|
@@ -174,7 +174,9 @@ export async function runCodexAppServerWorkspaceWriteRun(options) {
|
|
|
174
174
|
let contextRuntimeHint;
|
|
175
175
|
try {
|
|
176
176
|
skillInputs = resolveCodexAppServerSkillInputs({
|
|
177
|
-
...(options.skillSelectionName === undefined
|
|
177
|
+
...(options.skillSelectionName === undefined
|
|
178
|
+
? {}
|
|
179
|
+
: { selectionName: options.skillSelectionName }),
|
|
178
180
|
...(options.userSkillsRoot === undefined ? {} : { userSkillsRoot: options.userSkillsRoot }),
|
|
179
181
|
...(options.builtInSkillsRoot === undefined
|
|
180
182
|
? {}
|
|
@@ -182,11 +184,18 @@ export async function runCodexAppServerWorkspaceWriteRun(options) {
|
|
|
182
184
|
});
|
|
183
185
|
skillsListWarmup = resolveCodexAppServerSkillsListWarmup({
|
|
184
186
|
cwd: options.workspaceRoot,
|
|
185
|
-
...(options.skillSelectionName === undefined
|
|
187
|
+
...(options.skillSelectionName === undefined
|
|
188
|
+
? {}
|
|
189
|
+
: { selectionName: options.skillSelectionName }),
|
|
186
190
|
...(options.userSkillsRoot === undefined ? {} : { userSkillsRoot: options.userSkillsRoot }),
|
|
187
191
|
});
|
|
188
192
|
contextRuntimeHint = resolveCodexAppServerContextRuntimeHint({
|
|
189
|
-
...(options.
|
|
193
|
+
...(options.approvalContext?.activityRef === undefined
|
|
194
|
+
? {}
|
|
195
|
+
: { activityRef: options.approvalContext.activityRef }),
|
|
196
|
+
...(options.skillSelectionName === undefined
|
|
197
|
+
? {}
|
|
198
|
+
: { selectionName: options.skillSelectionName }),
|
|
190
199
|
...(options.agentContext === undefined ? {} : { agentContext: options.agentContext }),
|
|
191
200
|
});
|
|
192
201
|
}
|
|
@@ -264,10 +273,7 @@ export async function runCodexAppServerWorkspaceWriteRun(options) {
|
|
|
264
273
|
...entry.extraUserRoots,
|
|
265
274
|
]) ?? []),
|
|
266
275
|
];
|
|
267
|
-
const strictLeakCheckValues = [
|
|
268
|
-
options.apiKey,
|
|
269
|
-
...(contextRuntimeHint?.sensitiveValues ?? []),
|
|
270
|
-
];
|
|
276
|
+
const strictLeakCheckValues = [options.apiKey, ...(contextRuntimeHint?.sensitiveValues ?? [])];
|
|
271
277
|
let primaryError;
|
|
272
278
|
let runResult;
|
|
273
279
|
let lifecycleError;
|
|
@@ -336,9 +342,7 @@ export async function runCodexAppServerWorkspaceWriteRun(options) {
|
|
|
336
342
|
input: buildCodexAppServerTurnInput({
|
|
337
343
|
prompt: options.prompt,
|
|
338
344
|
skills: skillInputs,
|
|
339
|
-
...(contextRuntimeHint === undefined
|
|
340
|
-
? {}
|
|
341
|
-
: { runtimeHints: [contextRuntimeHint.text] }),
|
|
345
|
+
...(contextRuntimeHint === undefined ? {} : { runtimeHints: [contextRuntimeHint.text] }),
|
|
342
346
|
}),
|
|
343
347
|
cwd: options.workspaceRoot,
|
|
344
348
|
approvalPolicy,
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export declare class ReferenceCacheError extends Error {
|
|
2
|
+
readonly code: string;
|
|
3
|
+
constructor(code: string);
|
|
4
|
+
}
|
|
5
|
+
export type ReferenceCopy = {
|
|
6
|
+
source_ref: string;
|
|
7
|
+
revision: string;
|
|
8
|
+
sha256: string;
|
|
9
|
+
path: string;
|
|
10
|
+
size_bytes: number;
|
|
11
|
+
media_type: string;
|
|
12
|
+
checked_at: string;
|
|
13
|
+
};
|
|
14
|
+
export type ReferenceFetchResult = {
|
|
15
|
+
revision: string;
|
|
16
|
+
media_type: string;
|
|
17
|
+
content: Uint8Array;
|
|
18
|
+
};
|
|
19
|
+
export declare class ExternalReferenceCache {
|
|
20
|
+
private readonly options;
|
|
21
|
+
private readonly workspace;
|
|
22
|
+
private readonly ledgerFile;
|
|
23
|
+
private readonly ledger;
|
|
24
|
+
private tail;
|
|
25
|
+
constructor(options: {
|
|
26
|
+
workspaceRoot: string;
|
|
27
|
+
ledgerRoot: string;
|
|
28
|
+
now?: () => number;
|
|
29
|
+
maxTotalBytes?: number;
|
|
30
|
+
retentionMs?: number;
|
|
31
|
+
});
|
|
32
|
+
private now;
|
|
33
|
+
private validateLedger;
|
|
34
|
+
private save;
|
|
35
|
+
private bytes;
|
|
36
|
+
/** A pin belongs to a server-issued invocation, never to model-supplied identity. */
|
|
37
|
+
acquire(input: {
|
|
38
|
+
sourceRef: string;
|
|
39
|
+
invocationRef: string;
|
|
40
|
+
expiresAt: number;
|
|
41
|
+
fetch: () => Promise<ReferenceFetchResult>;
|
|
42
|
+
}): Promise<{
|
|
43
|
+
copy: ReferenceCopy;
|
|
44
|
+
cache_hit: boolean;
|
|
45
|
+
content: Buffer;
|
|
46
|
+
}>;
|
|
47
|
+
private projection;
|
|
48
|
+
private prune;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=cache.d.ts.map
|