@cursor/july 0.1.114 → 0.2.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/dist/channels/slack/channel-watch.d.ts +19 -3
- package/dist/channels/slack/channel-watch.d.ts.map +1 -1
- package/dist/channels/slack/channel-watch.js +48 -9
- package/dist/channels/slack/inbound.d.ts +7 -0
- package/dist/channels/slack/inbound.d.ts.map +1 -1
- package/dist/channels/slack/inbound.js +23 -0
- package/dist/channels/slack/slack-channel.d.ts.map +1 -1
- package/dist/channels/slack/slack-channel.js +87 -8
- package/dist/channels/slack/types.d.ts +11 -12
- package/dist/channels/slack/types.d.ts.map +1 -1
- package/dist/docs/404.html +2 -2
- package/dist/docs/assets/{app.BqkJwOZ-.js → app.D23Y-7Tp.js} +4 -4
- package/dist/docs/assets/chunks/@localSearchIndexroot.CzCCM7N8.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.BJAi2KiV.js → VPLocalSearchBox.CWBeTFRZ.js} +1 -1
- package/dist/docs/assets/chunks/{arc.BZpXTgvV.js → arc.DSF2O3pm.js} +1 -1
- package/dist/docs/assets/chunks/{architectureDiagram-Q4EWVU46.WYI-7F-Y.js → architectureDiagram-Q4EWVU46.J52Wzbkg.js} +1 -1
- package/dist/docs/assets/chunks/{baseUniq.CZaUPpg0.js → baseUniq.CQS3LPCt.js} +1 -1
- package/dist/docs/assets/chunks/{blockDiagram-DXYQGD6D.D6UES2pD.js → blockDiagram-DXYQGD6D.Dw339Gr5.js} +1 -1
- package/dist/docs/assets/chunks/{c4Diagram-AHTNJAMY.cwebIe4i.js → c4Diagram-AHTNJAMY.BUdtOaRZ.js} +1 -1
- package/dist/docs/assets/chunks/channel.Bfu4df88.js +1 -0
- package/dist/docs/assets/chunks/{chunk-4BX2VUAB.fVyFnjxg.js → chunk-4BX2VUAB.CuOrkEqk.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-4TB4RGXK.BanufG1c.js → chunk-4TB4RGXK.BJNBcY7U.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-55IACEB6.VaSMz5-2.js → chunk-55IACEB6.VJK5LAm_.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-EDXVE4YY.CN2diZOM.js → chunk-EDXVE4YY.BYYLihvj.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-FMBD7UC4.g4ivypu3.js → chunk-FMBD7UC4.CmoW8BXP.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-OYMX7WX6.GZXKn9JJ.js → chunk-OYMX7WX6.DTGY4C-M.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-QZHKN3VN.itXxJZCd.js → chunk-QZHKN3VN.Cg5n67vl.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-YZCP3GAM.-rw2GfvX.js → chunk-YZCP3GAM.C3GR_ia5.js} +1 -1
- package/dist/docs/assets/chunks/classDiagram-6PBFFD2Q.DdfgtaWs.js +1 -0
- package/dist/docs/assets/chunks/classDiagram-v2-HSJHXN6E.DdfgtaWs.js +1 -0
- package/dist/docs/assets/chunks/clone.rkmfti6d.js +1 -0
- package/dist/docs/assets/chunks/{cose-bilkent-S5V4N54A.CmaI5br0.js → cose-bilkent-S5V4N54A.BTRG8N3b.js} +1 -1
- package/dist/docs/assets/chunks/{dagre-KV5264BT.4wY9S4Kt.js → dagre-KV5264BT.Bob_bp_p.js} +1 -1
- package/dist/docs/assets/chunks/{diagram-5BDNPKRD.Pc3c0u9W.js → diagram-5BDNPKRD.ggPcs9uO.js} +1 -1
- package/dist/docs/assets/chunks/{diagram-G4DWMVQ6.CYrWz-nj.js → diagram-G4DWMVQ6.BP0qyJkp.js} +1 -1
- package/dist/docs/assets/chunks/{diagram-MMDJMWI5.Bgj5hukb.js → diagram-MMDJMWI5.B0X24UKr.js} +1 -1
- package/dist/docs/assets/chunks/{diagram-TYMM5635.DGMEXalS.js → diagram-TYMM5635.B4rXHFVt.js} +1 -1
- package/dist/docs/assets/chunks/{erDiagram-SMLLAGMA.GepTV9Im.js → erDiagram-SMLLAGMA._55Rt9oX.js} +1 -1
- package/dist/docs/assets/chunks/{flowDiagram-DWJPFMVM.DVKywg3j.js → flowDiagram-DWJPFMVM.DGP4XvR5.js} +1 -1
- package/dist/docs/assets/chunks/{ganttDiagram-T4ZO3ILL.C7qt9Mlo.js → ganttDiagram-T4ZO3ILL.BtXtkL4E.js} +1 -1
- package/dist/docs/assets/chunks/{gitGraphDiagram-UUTBAWPF.U30_r82P.js → gitGraphDiagram-UUTBAWPF.B9cPWblK.js} +1 -1
- package/dist/docs/assets/chunks/{graph.CyyMyAWv.js → graph.D8HzNexS.js} +1 -1
- package/dist/docs/assets/chunks/{infoDiagram-42DDH7IO.Dn9ACW3y.js → infoDiagram-42DDH7IO.Bw7CQUpi.js} +1 -1
- package/dist/docs/assets/chunks/{ishikawaDiagram-UXIWVN3A.DlIdIGOA.js → ishikawaDiagram-UXIWVN3A.MwkzF6nQ.js} +1 -1
- package/dist/docs/assets/chunks/{journeyDiagram-VCZTEJTY.DZj4vy4E.js → journeyDiagram-VCZTEJTY.DIGFF-3C.js} +1 -1
- package/dist/docs/assets/chunks/{kanban-definition-6JOO6SKY.Dl63eMUV.js → kanban-definition-6JOO6SKY.DhYef2BN.js} +1 -1
- package/dist/docs/assets/chunks/{layout.BLHZLWPH.js → layout.C0XUxuPi.js} +1 -1
- package/dist/docs/assets/chunks/{linear.aXKGKaNw.js → linear.BwNPpZex.js} +1 -1
- package/dist/docs/assets/chunks/{min.zWnFcpcc.js → min.CwAQdL7z.js} +1 -1
- package/dist/docs/assets/chunks/{mindmap-definition-QFDTVHPH.Qs4MQBea.js → mindmap-definition-QFDTVHPH.pWsSVLsP.js} +1 -1
- package/dist/docs/assets/chunks/{pieDiagram-DEJITSTG.BmPHgsk7.js → pieDiagram-DEJITSTG.BDJ3FbBy.js} +1 -1
- package/dist/docs/assets/chunks/{quadrantDiagram-34T5L4WZ.D5MQ3gwA.js → quadrantDiagram-34T5L4WZ.Co80izyB.js} +1 -1
- package/dist/docs/assets/chunks/{requirementDiagram-MS252O5E.CkdUFrO7.js → requirementDiagram-MS252O5E.JveKw4yx.js} +1 -1
- package/dist/docs/assets/chunks/{sankeyDiagram-XADWPNL6.KZrljrAV.js → sankeyDiagram-XADWPNL6.B0A7adPi.js} +1 -1
- package/dist/docs/assets/chunks/{sequenceDiagram-FGHM5R23.XMoEW-Lx.js → sequenceDiagram-FGHM5R23.d6JZ5Hre.js} +1 -1
- package/dist/docs/assets/chunks/{stateDiagram-FHFEXIEX.BmTzePLj.js → stateDiagram-FHFEXIEX.DWnL0NQl.js} +1 -1
- package/dist/docs/assets/chunks/stateDiagram-v2-QKLJ7IA2.ZEetPk0E.js +1 -0
- package/dist/docs/assets/chunks/{theme.BfQzpxsg.js → theme.MJTLx0hh.js} +2 -2
- package/dist/docs/assets/chunks/{timeline-definition-GMOUNBTQ.Dug0oamp.js → timeline-definition-GMOUNBTQ.CFS7Ai4c.js} +1 -1
- package/dist/docs/assets/chunks/{vennDiagram-DHZGUBPP.BOTHrEFu.js → vennDiagram-DHZGUBPP.CwSlnjCf.js} +1 -1
- package/dist/docs/assets/chunks/wardley-RL74JXVD.3gurI8YA.js +162 -0
- package/dist/docs/assets/chunks/{wardleyDiagram-NUSXRM2D.CoXKdfi6.js → wardleyDiagram-NUSXRM2D.B_8mvtjh.js} +1 -1
- package/dist/docs/assets/chunks/{xychartDiagram-5P7HB3ND.DXoSCjAW.js → xychartDiagram-5P7HB3ND.DtjU5H85.js} +1 -1
- package/dist/docs/assets/{guides_slack.md.Bo96y42E.js → guides_slack.md.Bjw2r2gL.js} +5 -5
- package/dist/docs/assets/{guides_slack.md.Bo96y42E.lean.js → guides_slack.md.Bjw2r2gL.lean.js} +1 -1
- package/dist/docs/assets/reference_cli.md.BvnQM8wd.js +97 -0
- package/dist/docs/assets/reference_cli.md.BvnQM8wd.lean.js +1 -0
- package/dist/docs/building-with-agents.html +35 -35
- package/dist/docs/deployment.html +35 -35
- package/dist/docs/evals.html +35 -35
- package/dist/docs/guides/agent-to-agent.html +35 -35
- package/dist/docs/guides/bitbucket.html +35 -35
- package/dist/docs/guides/cloud-agents.html +35 -35
- package/dist/docs/guides/convert-automation.html +35 -35
- package/dist/docs/guides/github.html +35 -35
- package/dist/docs/guides/gitlab.html +35 -35
- package/dist/docs/guides/grokbot-agents.html +35 -35
- package/dist/docs/guides/hooks.html +35 -35
- package/dist/docs/guides/improve.html +35 -35
- package/dist/docs/guides/jev.html +35 -35
- package/dist/docs/guides/mcp-oauth.html +35 -35
- package/dist/docs/guides/opentelemetry.html +35 -35
- package/dist/docs/guides/slack.html +39 -39
- package/dist/docs/guides/slack.md +16 -1
- package/dist/docs/guides/webhooks.html +35 -35
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +35 -35
- package/dist/docs/index.html +35 -35
- package/dist/docs/llms-full.txt +699 -752
- package/dist/docs/llms.txt +1 -1
- package/dist/docs/quickstart.html +35 -35
- package/dist/docs/reference/agent-config.html +35 -35
- package/dist/docs/reference/artifacts.html +35 -35
- package/dist/docs/reference/channels.html +35 -35
- package/dist/docs/reference/cli.html +127 -125
- package/dist/docs/reference/cli.md +685 -753
- package/dist/docs/reference/connections.html +35 -35
- package/dist/docs/reference/evals.html +35 -35
- package/dist/docs/reference/extensions.html +35 -35
- package/dist/docs/reference/hooks.html +35 -35
- package/dist/docs/reference/http-api.html +35 -35
- package/dist/docs/reference/instructions.html +35 -35
- package/dist/docs/reference/playground.html +35 -35
- package/dist/docs/reference/project-layout.html +35 -35
- package/dist/docs/reference/prompt.html +35 -35
- package/dist/docs/reference/schedules.html +35 -35
- package/dist/docs/reference/sessions.html +35 -35
- package/dist/docs/reference/skills.html +35 -35
- package/dist/docs/reference/subagents.html +35 -35
- package/dist/docs/reference/tools.html +35 -35
- package/dist/docs/templates/agentic-owners.html +35 -35
- package/dist/docs/templates/pr-autofixer.html +35 -35
- package/dist/docs/templates/security-reviewer.html +35 -35
- package/dist/docs/templates/thermo-quality-review.html +35 -35
- package/dist/docs/templates/thermo-review.html +35 -35
- package/dist/docs/templates/triage.html +35 -35
- package/dist/docs/troubleshooting.html +35 -35
- package/dist/files-backends/cursor-hosted.d.ts +11 -17
- package/dist/files-backends/cursor-hosted.d.ts.map +1 -1
- package/dist/files-backends/cursor-hosted.js +13 -41
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/internal/artifacts-store.d.ts +11 -0
- package/dist/internal/artifacts-store.d.ts.map +1 -1
- package/dist/internal/artifacts-store.js +113 -18
- package/dist/internal/cli-deploy.d.ts.map +1 -1
- package/dist/internal/cli-deploy.js +9 -1
- package/dist/internal/cursor/cursor-api-transport.d.ts +37 -0
- package/dist/internal/cursor/cursor-api-transport.d.ts.map +1 -0
- package/dist/internal/cursor/cursor-api-transport.js +44 -0
- package/dist/internal/cursor/hosted-store-secrets.d.ts +21 -0
- package/dist/internal/cursor/hosted-store-secrets.d.ts.map +1 -1
- package/dist/internal/cursor/hosted-store-secrets.js +26 -0
- package/dist/internal/cursor/store-api-client.d.ts +82 -0
- package/dist/internal/cursor/store-api-client.d.ts.map +1 -0
- package/dist/internal/cursor/store-api-client.js +227 -0
- package/dist/internal/deploy-client.d.ts +6 -0
- package/dist/internal/deploy-client.d.ts.map +1 -1
- package/dist/internal/deploy-client.js +3 -0
- package/dist/internal/deploy-manifest.d.ts +8 -0
- package/dist/internal/deploy-manifest.d.ts.map +1 -1
- package/dist/internal/deploy-manifest.js +7 -1
- package/dist/internal/discovery/agent-config.d.ts +3 -1
- package/dist/internal/discovery/agent-config.d.ts.map +1 -1
- package/dist/internal/discovery/agent-config.js +7 -4
- package/dist/internal/framework-storage-selection.d.ts +1 -1
- package/dist/internal/framework-storage-selection.d.ts.map +1 -1
- package/dist/internal/platform-timers.d.ts.map +1 -1
- package/dist/internal/platform-timers.js +20 -2
- package/dist/internal/reminder-runner.d.ts +79 -1
- package/dist/internal/reminder-runner.d.ts.map +1 -1
- package/dist/internal/reminder-runner.js +287 -46
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +7 -0
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +13 -15
- package/dist/internal/store-api-protocol.d.ts +134 -0
- package/dist/internal/store-api-protocol.d.ts.map +1 -0
- package/dist/internal/store-api-protocol.js +126 -0
- package/dist/memory.d.ts +49 -10
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +193 -50
- package/dist/playground/assets/{index-CrMWlgUU.js → index-Cs0MKsv4.js} +30 -30
- package/dist/playground/assets/index-DLwnR9ys.css +1 -0
- package/dist/playground/index.html +2 -2
- package/dist/reminders.d.ts +1 -1
- package/dist/reminders.d.ts.map +1 -1
- package/dist/types.d.ts +44 -10
- package/dist/types.d.ts.map +1 -1
- package/docs/guides/slack.md +16 -1
- package/docs/reference/cli.md +686 -754
- package/package.json +1 -1
- package/skills/setup-slack/SKILL.md +1 -1
- package/src/channels/slack/channel-watch.ts +57 -8
- package/src/channels/slack/inbound.ts +24 -0
- package/src/channels/slack/slack-channel.ts +127 -4
- package/src/channels/slack/types.ts +11 -12
- package/src/files-backends/cursor-hosted.ts +31 -68
- package/src/index.ts +1 -0
- package/src/internal/artifacts-store.ts +131 -25
- package/src/internal/cli-deploy.ts +12 -1
- package/src/internal/cursor/cursor-api-transport.ts +73 -0
- package/src/internal/cursor/hosted-store-secrets.ts +35 -0
- package/src/internal/cursor/store-api-client.ts +360 -0
- package/src/internal/deploy-client.ts +9 -0
- package/src/internal/deploy-manifest.ts +15 -0
- package/src/internal/discovery/agent-config.ts +8 -6
- package/src/internal/framework-storage-selection.ts +1 -1
- package/src/internal/platform-timers.ts +24 -2
- package/src/internal/reminder-runner.ts +454 -66
- package/src/internal/server.ts +8 -0
- package/src/internal/session-engine.ts +17 -22
- package/src/internal/store-api-protocol.ts +222 -0
- package/src/memory.ts +240 -59
- package/src/reminders.ts +1 -0
- package/src/types.ts +47 -10
- package/dist/docs/assets/chunks/@localSearchIndexroot.BnSgidYE.js +0 -1
- package/dist/docs/assets/chunks/channel.DdM5EfNW.js +0 -1
- package/dist/docs/assets/chunks/classDiagram-6PBFFD2Q.CjfGHeg2.js +0 -1
- package/dist/docs/assets/chunks/classDiagram-v2-HSJHXN6E.CjfGHeg2.js +0 -1
- package/dist/docs/assets/chunks/clone.wSOICb_f.js +0 -1
- package/dist/docs/assets/chunks/stateDiagram-v2-QKLJ7IA2.Cu5X28zZ.js +0 -1
- package/dist/docs/assets/chunks/wardley-RL74JXVD.DXy2i1LS.js +0 -162
- package/dist/docs/assets/reference_cli.md.DLWDz9ij.js +0 -95
- package/dist/docs/assets/reference_cli.md.DLWDz9ij.lean.js +0 -1
- package/dist/playground/assets/index-C61EWMBK.css +0 -1
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Domain-call wire contract for the factory store API:
|
|
3
|
+
* `POST /internal/agentsdk/store/api/<call>` carrying a versioned JSON
|
|
4
|
+
* envelope `{ v, call, payload }`. This is the lane where the **server** owns
|
|
5
|
+
* the storage pattern (journal sharding, rotation, compaction), so a
|
|
6
|
+
* pathological pattern is fixable in a backend deploy instead of a July
|
|
7
|
+
* release plus a rebake of every deployment. The verb lane (`/flush`,
|
|
8
|
+
* `/read`, `/list`) keeps carrying bulk presigned file IO.
|
|
9
|
+
*
|
|
10
|
+
* Deliberately duplicated on the backend
|
|
11
|
+
* (`backend/server/src/factory/agent-sdk/agentsdkStoreApiProtocol.ts`): this
|
|
12
|
+
* package is published to npm, so the backend cannot depend on it and it
|
|
13
|
+
* cannot depend on backend packages. A backend drift test compares the two
|
|
14
|
+
* sources — same shape as the hosted-delivery protocol twins — which is why
|
|
15
|
+
* every exported constant here stays a single `export const NAME = <literal>;`
|
|
16
|
+
* line and every schema field stays on its own line.
|
|
17
|
+
*
|
|
18
|
+
* Evolution rules (the compat contract): additive optional fields only; no
|
|
19
|
+
* renames, no retypes, no semantic reuse of an old field; unknown fields are
|
|
20
|
+
* ignored, never rejected; removing a field means deprecating it in place
|
|
21
|
+
* forever. A breaking change means a new `v`, and the server keeps serving
|
|
22
|
+
* every previous `v`.
|
|
23
|
+
*/
|
|
24
|
+
import { z } from "zod";
|
|
25
|
+
export declare const STORE_API_PROTOCOL_VERSION = 1;
|
|
26
|
+
/** Path family on the factory surface; one segment per call. */
|
|
27
|
+
export declare const STORE_API_PATH = "/internal/agentsdk/store/api";
|
|
28
|
+
export declare const STORE_API_MEMORY_APPEND_CALL = "memory.append";
|
|
29
|
+
/**
|
|
30
|
+
* Semantic cap on one serialized memory record. Text fields are truncated
|
|
31
|
+
* client-side (`memoryHook` default 2000 chars per field), so a well-formed
|
|
32
|
+
* record is a few KiB; 16 KiB is generous headroom, not a target. The cap is
|
|
33
|
+
* part of the wire contract but rides the layers, not the schema: the
|
|
34
|
+
* backend's store controller enforces it as a typed 4xx, and the store API
|
|
35
|
+
* client (`cursor/store-api-client.ts`) pre-checks it before spending a
|
|
36
|
+
* doomed request.
|
|
37
|
+
*/
|
|
38
|
+
export declare const MEMORY_APPEND_MAX_RECORD_BYTES: number;
|
|
39
|
+
/** Serialized size of a record, as counted against the byte cap. */
|
|
40
|
+
export declare function serializedRecordBytes(record: unknown): number;
|
|
41
|
+
/**
|
|
42
|
+
* One turn's memory record as it crosses the wire — July's
|
|
43
|
+
* `TurnMemoryRecord` (memory.ts). The extra-key record mirrors the schema's
|
|
44
|
+
* `.passthrough()`: a newer client's additive optional fields are journaled
|
|
45
|
+
* verbatim rather than stripped by an older server.
|
|
46
|
+
*/
|
|
47
|
+
export type TurnMemoryRecordWire = {
|
|
48
|
+
at: string;
|
|
49
|
+
sessionId: string;
|
|
50
|
+
channelId: string;
|
|
51
|
+
status: "completed" | "failed";
|
|
52
|
+
title?: string;
|
|
53
|
+
sdkAgentId?: string;
|
|
54
|
+
userMessage?: string;
|
|
55
|
+
result?: string;
|
|
56
|
+
usage?: Record<string, unknown>;
|
|
57
|
+
} & Record<string, unknown>;
|
|
58
|
+
/**
|
|
59
|
+
* Wire schema for {@link TurnMemoryRecordWire}. Per-field caps are
|
|
60
|
+
* deliberately absent: the client truncates text at authoring time and
|
|
61
|
+
* {@link MEMORY_APPEND_MAX_RECORD_BYTES} bounds the whole record.
|
|
62
|
+
*/
|
|
63
|
+
export declare const turnMemoryRecordWireSchema: z.ZodType<TurnMemoryRecordWire>;
|
|
64
|
+
/** `memory.append` validated payload. */
|
|
65
|
+
export type MemoryAppendPayload = {
|
|
66
|
+
agent: string;
|
|
67
|
+
record: TurnMemoryRecordWire;
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* `memory.append` payload shape. The agent name becomes a store key segment
|
|
71
|
+
* on the server, so it must be exactly one segment. Unknown payload fields
|
|
72
|
+
* are stripped (= ignored), per the evolution rules. The byte cap is
|
|
73
|
+
* semantics, not shape — the backend's store controller owns it.
|
|
74
|
+
*/
|
|
75
|
+
export declare const memoryAppendPayloadSchema: z.ZodType<MemoryAppendPayload>;
|
|
76
|
+
/** The versioned request body for the `memory.append` call. */
|
|
77
|
+
export type MemoryAppendEnvelope = {
|
|
78
|
+
v: typeof STORE_API_PROTOCOL_VERSION;
|
|
79
|
+
call: typeof STORE_API_MEMORY_APPEND_CALL;
|
|
80
|
+
payload: MemoryAppendPayload;
|
|
81
|
+
};
|
|
82
|
+
/** The whole request body. Unknown envelope fields are stripped (= ignored). */
|
|
83
|
+
export declare const memoryAppendEnvelopeSchema: z.ZodType<MemoryAppendEnvelope>;
|
|
84
|
+
/** `memory.append` success body. */
|
|
85
|
+
export type MemoryAppendResponse = {
|
|
86
|
+
v: typeof STORE_API_PROTOCOL_VERSION;
|
|
87
|
+
ok: true;
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* Success body. Failures answer the store surface's standard error JSON
|
|
91
|
+
* (`{ code, error }`) with a matching HTTP status.
|
|
92
|
+
*/
|
|
93
|
+
export declare const memoryAppendResponseSchema: z.ZodType<MemoryAppendResponse>;
|
|
94
|
+
export declare const STORE_API_MEMORY_READ_CALL = "memory.read";
|
|
95
|
+
/** `memory.read` validated payload. */
|
|
96
|
+
export type MemoryReadPayload = {
|
|
97
|
+
agent: string;
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* `memory.read` payload shape — the same single-segment agent name rule as
|
|
101
|
+
* `memory.append`, since the name addresses the same journal key family.
|
|
102
|
+
*/
|
|
103
|
+
export declare const memoryReadPayloadSchema: z.ZodType<MemoryReadPayload>;
|
|
104
|
+
/** The versioned request body for the `memory.read` call. */
|
|
105
|
+
export type MemoryReadEnvelope = {
|
|
106
|
+
v: typeof STORE_API_PROTOCOL_VERSION;
|
|
107
|
+
call: typeof STORE_API_MEMORY_READ_CALL;
|
|
108
|
+
payload: MemoryReadPayload;
|
|
109
|
+
};
|
|
110
|
+
/** The whole request body. Unknown envelope fields are stripped (= ignored). */
|
|
111
|
+
export declare const memoryReadEnvelopeSchema: z.ZodType<MemoryReadEnvelope>;
|
|
112
|
+
/**
|
|
113
|
+
* `memory.read` success body. The call is flush-on-read: the server drains
|
|
114
|
+
* the agent's pending append buffer before presigning. Best-effort: when
|
|
115
|
+
* the drain succeeds the journal includes every append that preceded the
|
|
116
|
+
* read; a busy flush lock, a buffer outage, or an oversized backlog
|
|
117
|
+
* degrades to the already-flushed state (callers must not regress their
|
|
118
|
+
* local view on a shorter download). `journal` is null while the agent has
|
|
119
|
+
* no journal at all.
|
|
120
|
+
*/
|
|
121
|
+
export type MemoryReadResponse = {
|
|
122
|
+
v: typeof STORE_API_PROTOCOL_VERSION;
|
|
123
|
+
ok: true;
|
|
124
|
+
journal: {
|
|
125
|
+
url: string;
|
|
126
|
+
expiresAt: string;
|
|
127
|
+
} | null;
|
|
128
|
+
};
|
|
129
|
+
/**
|
|
130
|
+
* Success body. Failures answer the store surface's standard error JSON
|
|
131
|
+
* (`{ code, error }`) with a matching HTTP status.
|
|
132
|
+
*/
|
|
133
|
+
export declare const memoryReadResponseSchema: z.ZodType<MemoryReadResponse>;
|
|
134
|
+
//# sourceMappingURL=store-api-protocol.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store-api-protocol.d.ts","sourceRoot":"","sources":["../../src/internal/store-api-protocol.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Domain-call wire contract for the factory store API:
|
|
3
|
+
* `POST /internal/agentsdk/store/api/<call>` carrying a versioned JSON
|
|
4
|
+
* envelope `{ v, call, payload }`. This is the lane where the **server** owns
|
|
5
|
+
* the storage pattern (journal sharding, rotation, compaction), so a
|
|
6
|
+
* pathological pattern is fixable in a backend deploy instead of a July
|
|
7
|
+
* release plus a rebake of every deployment. The verb lane (`/flush`,
|
|
8
|
+
* `/read`, `/list`) keeps carrying bulk presigned file IO.
|
|
9
|
+
*
|
|
10
|
+
* Deliberately duplicated on the backend
|
|
11
|
+
* (`backend/server/src/factory/agent-sdk/agentsdkStoreApiProtocol.ts`): this
|
|
12
|
+
* package is published to npm, so the backend cannot depend on it and it
|
|
13
|
+
* cannot depend on backend packages. A backend drift test compares the two
|
|
14
|
+
* sources — same shape as the hosted-delivery protocol twins — which is why
|
|
15
|
+
* every exported constant here stays a single `export const NAME = <literal>;`
|
|
16
|
+
* line and every schema field stays on its own line.
|
|
17
|
+
*
|
|
18
|
+
* Evolution rules (the compat contract): additive optional fields only; no
|
|
19
|
+
* renames, no retypes, no semantic reuse of an old field; unknown fields are
|
|
20
|
+
* ignored, never rejected; removing a field means deprecating it in place
|
|
21
|
+
* forever. A breaking change means a new `v`, and the server keeps serving
|
|
22
|
+
* every previous `v`.
|
|
23
|
+
*/
|
|
24
|
+
import { z } from "zod";
|
|
25
|
+
export const STORE_API_PROTOCOL_VERSION = 1;
|
|
26
|
+
/** Path family on the factory surface; one segment per call. */
|
|
27
|
+
export const STORE_API_PATH = "/internal/agentsdk/store/api";
|
|
28
|
+
export const STORE_API_MEMORY_APPEND_CALL = "memory.append";
|
|
29
|
+
/**
|
|
30
|
+
* Semantic cap on one serialized memory record. Text fields are truncated
|
|
31
|
+
* client-side (`memoryHook` default 2000 chars per field), so a well-formed
|
|
32
|
+
* record is a few KiB; 16 KiB is generous headroom, not a target. The cap is
|
|
33
|
+
* part of the wire contract but rides the layers, not the schema: the
|
|
34
|
+
* backend's store controller enforces it as a typed 4xx, and the store API
|
|
35
|
+
* client (`cursor/store-api-client.ts`) pre-checks it before spending a
|
|
36
|
+
* doomed request.
|
|
37
|
+
*/
|
|
38
|
+
export const MEMORY_APPEND_MAX_RECORD_BYTES = 16 * 1024;
|
|
39
|
+
/** Serialized size of a record, as counted against the byte cap. */
|
|
40
|
+
export function serializedRecordBytes(record) {
|
|
41
|
+
return new TextEncoder().encode(JSON.stringify(record)).byteLength;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Wire schema for {@link TurnMemoryRecordWire}. Per-field caps are
|
|
45
|
+
* deliberately absent: the client truncates text at authoring time and
|
|
46
|
+
* {@link MEMORY_APPEND_MAX_RECORD_BYTES} bounds the whole record.
|
|
47
|
+
*/
|
|
48
|
+
export const turnMemoryRecordWireSchema = z
|
|
49
|
+
.object({
|
|
50
|
+
at: z.string().min(1),
|
|
51
|
+
sessionId: z.string().min(1),
|
|
52
|
+
channelId: z.string().min(1),
|
|
53
|
+
status: z.enum(["completed", "failed"]),
|
|
54
|
+
title: z.string().optional(),
|
|
55
|
+
sdkAgentId: z.string().optional(),
|
|
56
|
+
userMessage: z.string().optional(),
|
|
57
|
+
result: z.string().optional(),
|
|
58
|
+
usage: z.object({}).passthrough().optional(),
|
|
59
|
+
})
|
|
60
|
+
.passthrough();
|
|
61
|
+
/**
|
|
62
|
+
* `memory.append` payload shape. The agent name becomes a store key segment
|
|
63
|
+
* on the server, so it must be exactly one segment. Unknown payload fields
|
|
64
|
+
* are stripped (= ignored), per the evolution rules. The byte cap is
|
|
65
|
+
* semantics, not shape — the backend's store controller owns it.
|
|
66
|
+
*/
|
|
67
|
+
export const memoryAppendPayloadSchema = z.object({
|
|
68
|
+
agent: z
|
|
69
|
+
.string()
|
|
70
|
+
.min(1)
|
|
71
|
+
.max(256)
|
|
72
|
+
.refine(name => !name.includes("/") &&
|
|
73
|
+
!name.includes("\\") &&
|
|
74
|
+
name !== "." &&
|
|
75
|
+
name !== "..", { message: "agent must be a single store key segment" }),
|
|
76
|
+
record: turnMemoryRecordWireSchema,
|
|
77
|
+
});
|
|
78
|
+
/** The whole request body. Unknown envelope fields are stripped (= ignored). */
|
|
79
|
+
export const memoryAppendEnvelopeSchema = z.object({
|
|
80
|
+
v: z.literal(STORE_API_PROTOCOL_VERSION),
|
|
81
|
+
call: z.literal(STORE_API_MEMORY_APPEND_CALL),
|
|
82
|
+
payload: memoryAppendPayloadSchema,
|
|
83
|
+
});
|
|
84
|
+
/**
|
|
85
|
+
* Success body. Failures answer the store surface's standard error JSON
|
|
86
|
+
* (`{ code, error }`) with a matching HTTP status.
|
|
87
|
+
*/
|
|
88
|
+
export const memoryAppendResponseSchema = z.object({
|
|
89
|
+
v: z.literal(STORE_API_PROTOCOL_VERSION),
|
|
90
|
+
ok: z.literal(true),
|
|
91
|
+
});
|
|
92
|
+
export const STORE_API_MEMORY_READ_CALL = "memory.read";
|
|
93
|
+
/**
|
|
94
|
+
* `memory.read` payload shape — the same single-segment agent name rule as
|
|
95
|
+
* `memory.append`, since the name addresses the same journal key family.
|
|
96
|
+
*/
|
|
97
|
+
export const memoryReadPayloadSchema = z.object({
|
|
98
|
+
agent: z
|
|
99
|
+
.string()
|
|
100
|
+
.min(1)
|
|
101
|
+
.max(256)
|
|
102
|
+
.refine(name => !name.includes("/") &&
|
|
103
|
+
!name.includes("\\") &&
|
|
104
|
+
name !== "." &&
|
|
105
|
+
name !== "..", { message: "agent must be a single store key segment" }),
|
|
106
|
+
});
|
|
107
|
+
/** The whole request body. Unknown envelope fields are stripped (= ignored). */
|
|
108
|
+
export const memoryReadEnvelopeSchema = z.object({
|
|
109
|
+
v: z.literal(STORE_API_PROTOCOL_VERSION),
|
|
110
|
+
call: z.literal(STORE_API_MEMORY_READ_CALL),
|
|
111
|
+
payload: memoryReadPayloadSchema,
|
|
112
|
+
});
|
|
113
|
+
/**
|
|
114
|
+
* Success body. Failures answer the store surface's standard error JSON
|
|
115
|
+
* (`{ code, error }`) with a matching HTTP status.
|
|
116
|
+
*/
|
|
117
|
+
export const memoryReadResponseSchema = z.object({
|
|
118
|
+
v: z.literal(STORE_API_PROTOCOL_VERSION),
|
|
119
|
+
ok: z.literal(true),
|
|
120
|
+
journal: z
|
|
121
|
+
.object({
|
|
122
|
+
url: z.string().min(1),
|
|
123
|
+
expiresAt: z.string().min(1),
|
|
124
|
+
})
|
|
125
|
+
.nullable(),
|
|
126
|
+
});
|
package/dist/memory.d.ts
CHANGED
|
@@ -18,11 +18,16 @@
|
|
|
18
18
|
*
|
|
19
19
|
* On Cursor-managed hosting the default is {@link agentStoreMemoryBackend}:
|
|
20
20
|
* the journal lives on the deployment's Agent Store (survives deploys,
|
|
21
|
-
* visible on cloud VMs under the store mount)
|
|
22
|
-
*
|
|
23
|
-
*
|
|
21
|
+
* visible on cloud VMs under the store mount), written exclusively through
|
|
22
|
+
* the `memory.append` domain call — the server owns the journal pattern —
|
|
23
|
+
* and mirrored to `<stateRoot>/memory/journal.jsonl` (hydrated per session
|
|
24
|
+
* via `memory.read`, appended locally per turn) so the workspace symlink
|
|
25
|
+
* read path keeps working for local-runtime turns. The
|
|
26
|
+
* `factory-api-v1` pin file exists only on hosted pods — plain local dev
|
|
27
|
+
* runs {@link fileMemoryBackend} and never sees the hosted lane.
|
|
24
28
|
*/
|
|
25
|
-
import { type
|
|
29
|
+
import { type CursorHostedFilesOptions } from "./files-backends/cursor-hosted.js";
|
|
30
|
+
import { type StoreApiClient } from "./internal/cursor/store-api-client.js";
|
|
26
31
|
import type { HookDefinition, TurnUsage } from "./types.js";
|
|
27
32
|
/** Name of the shared memory directory under the agent state root. */
|
|
28
33
|
export declare const MEMORY_DIR_NAME = "memory";
|
|
@@ -49,6 +54,16 @@ export interface MemoryBackend {
|
|
|
49
54
|
stateRoot: string;
|
|
50
55
|
agentName: string;
|
|
51
56
|
}): Promise<void>;
|
|
57
|
+
/**
|
|
58
|
+
* Optional session-start hook: bring the backend's local read path up to
|
|
59
|
+
* date before the session's first turn reads it. A freshness upgrade, not
|
|
60
|
+
* a correctness gate — implementations soft-fail and keep whatever read
|
|
61
|
+
* state already exists.
|
|
62
|
+
*/
|
|
63
|
+
prepareSession?(ctx: {
|
|
64
|
+
stateRoot: string;
|
|
65
|
+
agentName: string;
|
|
66
|
+
}): Promise<void>;
|
|
52
67
|
}
|
|
53
68
|
export interface FileMemoryBackendOptions {
|
|
54
69
|
/**
|
|
@@ -64,16 +79,40 @@ export interface FileMemoryBackendOptions {
|
|
|
64
79
|
*/
|
|
65
80
|
export declare function fileMemoryBackend(options?: FileMemoryBackendOptions): MemoryBackend;
|
|
66
81
|
export interface AgentStoreMemoryBackendOptions {
|
|
67
|
-
/**
|
|
68
|
-
|
|
69
|
-
|
|
82
|
+
/**
|
|
83
|
+
* Local mirror rotation threshold, same meaning as
|
|
84
|
+
* {@link FileMemoryBackendOptions}. The durable journal's rotation is the
|
|
85
|
+
* server's (`memory.append` controller), not this.
|
|
86
|
+
*/
|
|
70
87
|
maxJournalBytes?: number;
|
|
88
|
+
/**
|
|
89
|
+
* Cursor-hosted transport overrides (tests): base URL, credential, store
|
|
90
|
+
* source id, protocol pin, fetch. Feeds the default
|
|
91
|
+
* {@link storeApiClient} and the lane-availability check.
|
|
92
|
+
*/
|
|
93
|
+
hosted?: CursorHostedFilesOptions;
|
|
94
|
+
/**
|
|
95
|
+
* Domain-lane client override (tests). Defaults to
|
|
96
|
+
* {@link createStoreApiClient} over {@link hosted} — the module that owns
|
|
97
|
+
* the `memory.append` / `memory.read` transport, typed errors, and
|
|
98
|
+
* bounded backoff.
|
|
99
|
+
*/
|
|
100
|
+
storeApiClient?: StoreApiClient;
|
|
71
101
|
}
|
|
72
102
|
/**
|
|
73
103
|
* Journal on the deployment's Agent Store — durable across deploys, visible
|
|
74
|
-
* on cloud VMs under the store mount
|
|
75
|
-
*
|
|
76
|
-
*
|
|
104
|
+
* on cloud VMs under the store mount, written exclusively through the
|
|
105
|
+
* `memory.append` domain call: the server owns the journal's storage
|
|
106
|
+
* pattern (Redis-buffered flush, rotation), so a pathological pattern is
|
|
107
|
+
* fixable in a backend deploy instead of a July release plus a rebake.
|
|
108
|
+
*
|
|
109
|
+
* There is no client-composed fallback. The read-modify-write CAS lane that
|
|
110
|
+
* predated the domain call (and caused the 2026-09-18 Agent Store read
|
|
111
|
+
* storm) was removed in 0.2.1 together with v2 hosting binding the
|
|
112
|
+
* `factory-api-v1` pin unconditionally and refusing artifacts frozen on an
|
|
113
|
+
* older July. A hosted pod without the pin is therefore a misconfiguration
|
|
114
|
+
* (a server predating the pin change, or a local env naming a hosted store
|
|
115
|
+
* without one): records are dropped loudly, never written client-side.
|
|
77
116
|
*/
|
|
78
117
|
export declare function agentStoreMemoryBackend(options?: AgentStoreMemoryBackendOptions): MemoryBackend;
|
|
79
118
|
export interface MemoryHookOptions {
|
package/dist/memory.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAMH,OAAO,EACL,KAAK,wBAAwB,EAE9B,MAAM,mCAAmC,CAAC;AAE3C,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,KAAK,EAAe,cAAc,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEzE,sEAAsE;AACtE,eAAO,MAAM,eAAe,WAAW,CAAC;AAExC,gDAAgD;AAChD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,+CAA+C;IAC/C,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,WAAW,GAAG,QAAQ,CAAC;IAC/B,+CAA+C;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0DAA0D;IAC1D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4EAA4E;IAC5E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,SAAS,CAAC;CACnB,CAAC;AAEF,kFAAkF;AAClF,MAAM,WAAW,aAAa;IAC5B,UAAU,CACR,MAAM,EAAE,gBAAgB,EACxB,GAAG,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GAC5C,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB;;;;;OAKG;IACH,cAAc,CAAC,CAAC,GAAG,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/E;AAED,MAAM,WAAW,wBAAwB;IACvC;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,GAAE,wBAA6B,GACrC,aAAa,CAgCf;AAED,MAAM,WAAW,8BAA8B;IAC7C;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;OAIG;IACH,MAAM,CAAC,EAAE,wBAAwB,CAAC;IAClC;;;;;OAKG;IACH,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,GAAE,8BAAmC,GAC3C,aAAa,CAiMf;AAqBD,MAAM,WAAW,iBAAiB;IAChC,+DAA+D;IAC/D,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,yEAAyE;IACzE,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAMD;;;;;;;;;;;;GAYG;AACH,wBAAgB,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,cAAc,CA4G1E"}
|
package/dist/memory.js
CHANGED
|
@@ -18,9 +18,13 @@
|
|
|
18
18
|
*
|
|
19
19
|
* On Cursor-managed hosting the default is {@link agentStoreMemoryBackend}:
|
|
20
20
|
* the journal lives on the deployment's Agent Store (survives deploys,
|
|
21
|
-
* visible on cloud VMs under the store mount)
|
|
22
|
-
*
|
|
23
|
-
*
|
|
21
|
+
* visible on cloud VMs under the store mount), written exclusively through
|
|
22
|
+
* the `memory.append` domain call — the server owns the journal pattern —
|
|
23
|
+
* and mirrored to `<stateRoot>/memory/journal.jsonl` (hydrated per session
|
|
24
|
+
* via `memory.read`, appended locally per turn) so the workspace symlink
|
|
25
|
+
* read path keeps working for local-runtime turns. The
|
|
26
|
+
* `factory-api-v1` pin file exists only on hosted pods — plain local dev
|
|
27
|
+
* runs {@link fileMemoryBackend} and never sees the hosted lane.
|
|
24
28
|
*/
|
|
25
29
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
30
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
@@ -34,9 +38,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
34
38
|
import { randomUUID } from "node:crypto";
|
|
35
39
|
import { appendFile, mkdir, rename, stat, writeFile } from "node:fs/promises";
|
|
36
40
|
import { join } from "node:path";
|
|
37
|
-
import { agentStoreKeys
|
|
38
|
-
import {
|
|
41
|
+
import { agentStoreKeys } from "./files.js";
|
|
42
|
+
import { isCursorHostedFilesAvailable, } from "./files-backends/cursor-hosted.js";
|
|
39
43
|
import { defineHook } from "./hooks.js";
|
|
44
|
+
import { createStoreApiClient, isStoreApiLaneEnabled, } from "./internal/cursor/store-api-client.js";
|
|
40
45
|
/** Name of the shared memory directory under the agent state root. */
|
|
41
46
|
export const MEMORY_DIR_NAME = "memory";
|
|
42
47
|
/**
|
|
@@ -82,67 +87,187 @@ export function fileMemoryBackend(options = {}) {
|
|
|
82
87
|
}
|
|
83
88
|
/**
|
|
84
89
|
* Journal on the deployment's Agent Store — durable across deploys, visible
|
|
85
|
-
* on cloud VMs under the store mount
|
|
86
|
-
*
|
|
87
|
-
*
|
|
90
|
+
* on cloud VMs under the store mount, written exclusively through the
|
|
91
|
+
* `memory.append` domain call: the server owns the journal's storage
|
|
92
|
+
* pattern (Redis-buffered flush, rotation), so a pathological pattern is
|
|
93
|
+
* fixable in a backend deploy instead of a July release plus a rebake.
|
|
94
|
+
*
|
|
95
|
+
* There is no client-composed fallback. The read-modify-write CAS lane that
|
|
96
|
+
* predated the domain call (and caused the 2026-09-18 Agent Store read
|
|
97
|
+
* storm) was removed in 0.2.1 together with v2 hosting binding the
|
|
98
|
+
* `factory-api-v1` pin unconditionally and refusing artifacts frozen on an
|
|
99
|
+
* older July. A hosted pod without the pin is therefore a misconfiguration
|
|
100
|
+
* (a server predating the pin change, or a local env naming a hosted store
|
|
101
|
+
* without one): records are dropped loudly, never written client-side.
|
|
88
102
|
*/
|
|
89
103
|
export function agentStoreMemoryBackend(options = {}) {
|
|
90
|
-
var _a, _b;
|
|
91
|
-
const
|
|
104
|
+
var _a, _b, _c;
|
|
105
|
+
const hosted = (_a = options.hosted) !== null && _a !== void 0 ? _a : {};
|
|
92
106
|
const maxJournalBytes = (_b = options.maxJournalBytes) !== null && _b !== void 0 ? _b : 5 * 1024 * 1024;
|
|
93
|
-
//
|
|
94
|
-
//
|
|
107
|
+
// Mirror work is chained per journal key (same shape as
|
|
108
|
+
// fileMemoryBackend): hydration and appends on one agent's mirror never
|
|
109
|
+
// interleave, and a failed step must not poison the chain for later turns.
|
|
95
110
|
const appendChains = new Map();
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
111
|
+
// Transport, envelope, typed errors, and bounded backoff all live in the
|
|
112
|
+
// client; this module only decides which lane an append takes.
|
|
113
|
+
const storeApiClient = (_c = options.storeApiClient) !== null && _c !== void 0 ? _c : createStoreApiClient(hosted);
|
|
114
|
+
/**
|
|
115
|
+
* The domain lane still owes local-runtime sessions their read path:
|
|
116
|
+
* cloud-runtime turns read the journal through the store mount, but
|
|
117
|
+
* local-runtime turns on hosted pods (the default `runtime: "local"`)
|
|
118
|
+
* read `<stateRoot>/memory/journal.jsonl` via the workspace symlink, and
|
|
119
|
+
* on hosting the only writer of that file is this backend. So the lane
|
|
120
|
+
* keeps the mirror live without reintroducing the CAS read pattern:
|
|
121
|
+
* hydrate it once from the store when the file is absent (a fresh pod
|
|
122
|
+
* after a deploy), then append each successfully posted record locally,
|
|
123
|
+
* rotating at {@link maxJournalBytes} like {@link fileMemoryBackend}.
|
|
124
|
+
* Server-buffered records not yet flushed when a pod hydrates are the
|
|
125
|
+
* lane's documented staleness window (~30 s / 64 KiB), and other pods'
|
|
126
|
+
* appends surface on the next hydration — advisory memory, same envelope
|
|
127
|
+
* as the server side.
|
|
128
|
+
*/
|
|
129
|
+
const hydratedMirrors = new Set();
|
|
130
|
+
let mirrorRotationSeq = 0;
|
|
131
|
+
const maintainLocalMirror = (record, ctx) => __awaiter(this, void 0, void 0, function* () {
|
|
132
|
+
var _a;
|
|
133
|
+
var _b;
|
|
134
|
+
const dir = join(ctx.stateRoot, MEMORY_DIR_NAME);
|
|
135
|
+
const path = join(dir, "journal.jsonl");
|
|
136
|
+
if (!hydratedMirrors.has(path)) {
|
|
137
|
+
// Appends are chained per journal key, so this guard never races
|
|
138
|
+
// itself for one agent. Backstop for a session that appended before
|
|
139
|
+
// any prepareSession hydration ran (e.g. a custom hook ordering).
|
|
140
|
+
hydratedMirrors.add(path);
|
|
141
|
+
const existing = yield stat(path).catch(() => undefined);
|
|
142
|
+
if (existing === undefined) {
|
|
143
|
+
const content = yield storeApiClient.memoryReadContent({
|
|
144
|
+
agent: ctx.agentName,
|
|
122
145
|
});
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
if (error instanceof FileConflictError && attempt < 2) {
|
|
126
|
-
continue;
|
|
146
|
+
if (content !== undefined) {
|
|
147
|
+
yield mirrorJournalLocally(ctx.stateRoot, content);
|
|
127
148
|
}
|
|
128
|
-
throw error;
|
|
129
|
-
}
|
|
130
|
-
yield mirrorJournalLocally(ctx.stateRoot, next);
|
|
131
|
-
if (rotatedStamp !== undefined) {
|
|
132
|
-
// Rotated segments sit beside the live journal locally too, so the
|
|
133
|
-
// workspace symlink read path keeps pre-rotation history.
|
|
134
|
-
yield writeFile(join(ctx.stateRoot, MEMORY_DIR_NAME, `journal-${rotatedStamp}.jsonl`), currentBody);
|
|
135
149
|
}
|
|
150
|
+
}
|
|
151
|
+
yield mkdir(dir, { recursive: true });
|
|
152
|
+
const size = (_b = (_a = (yield stat(path).catch(() => undefined))) === null || _a === void 0 ? void 0 : _a.size) !== null && _b !== void 0 ? _b : 0;
|
|
153
|
+
if (size >= maxJournalBytes) {
|
|
154
|
+
mirrorRotationSeq += 1;
|
|
155
|
+
yield rename(path, join(dir, `journal-${Date.now()}-${mirrorRotationSeq}.jsonl`));
|
|
156
|
+
}
|
|
157
|
+
yield appendFile(path, `${JSON.stringify(record)}\n`, "utf8");
|
|
158
|
+
});
|
|
159
|
+
/**
|
|
160
|
+
* One `memory.append` domain call; the server appends to the server-owned
|
|
161
|
+
* journal. On success the record is also appended to the local mirror so
|
|
162
|
+
* the workspace symlink read path stays live (see
|
|
163
|
+
* {@link maintainLocalMirror}).
|
|
164
|
+
*
|
|
165
|
+
* Failure policy: log and give up for this record. Memory is advisory and
|
|
166
|
+
* the hook runner treats an append failure as non-fatal to the turn;
|
|
167
|
+
* falling back to the CAS path per-record would reintroduce the write
|
|
168
|
+
* storm under exactly the server brownout that makes this call fail. A
|
|
169
|
+
* failed POST also skips the mirror — the mirror must never show a record
|
|
170
|
+
* the durable journal will not have.
|
|
171
|
+
*/
|
|
172
|
+
const appendViaStoreApi = (record, ctx) => __awaiter(this, void 0, void 0, function* () {
|
|
173
|
+
try {
|
|
174
|
+
yield storeApiClient.memoryAppend({ agent: ctx.agentName, record });
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
console.warn(`[agent-serve] memory.append dropped one record for "${ctx.agentName}": ${error instanceof Error ? error.message : String(error)}`);
|
|
136
178
|
return;
|
|
137
179
|
}
|
|
180
|
+
try {
|
|
181
|
+
yield maintainLocalMirror(record, ctx);
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
console.warn(`[agent-serve] memory mirror update failed for "${ctx.agentName}" (journal record is durable): ${error instanceof Error ? error.message : String(error)}`);
|
|
185
|
+
}
|
|
138
186
|
});
|
|
187
|
+
/**
|
|
188
|
+
* Session-start hydration: one `memory.read` (flush-on-read server-side,
|
|
189
|
+
* so the pending buffer — including a burst another pod appended — lands
|
|
190
|
+
* first) and the mirror is rewritten to global state; the session then
|
|
191
|
+
* reads everything appended before it started. Soft-fail: a failed
|
|
192
|
+
* hydration keeps the existing mirror.
|
|
193
|
+
*/
|
|
194
|
+
const hydrateMirror = (ctx) => __awaiter(this, void 0, void 0, function* () {
|
|
195
|
+
var _a;
|
|
196
|
+
var _b;
|
|
197
|
+
const path = join(ctx.stateRoot, MEMORY_DIR_NAME, "journal.jsonl");
|
|
198
|
+
try {
|
|
199
|
+
const content = yield storeApiClient.memoryReadContent({
|
|
200
|
+
agent: ctx.agentName,
|
|
201
|
+
});
|
|
202
|
+
if (content !== undefined) {
|
|
203
|
+
// Never regress the read path: every mirrored record was
|
|
204
|
+
// server-acked before it was written locally, so a download SHORTER
|
|
205
|
+
// than the mirror means the server's flush-on-read was degraded (a
|
|
206
|
+
// busy lock, a Redis outage — the acked tail is still buffered) or
|
|
207
|
+
// the journal rotated. Keeping the richer mirror loses nothing;
|
|
208
|
+
// rewriting would hide records the agent has already seen.
|
|
209
|
+
const mirroredBytes = (_b = (_a = (yield stat(path).catch(() => undefined))) === null || _a === void 0 ? void 0 : _a.size) !== null && _b !== void 0 ? _b : 0;
|
|
210
|
+
if (content.byteLength >= mirroredBytes) {
|
|
211
|
+
yield mirrorJournalLocally(ctx.stateRoot, content);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
// Either way the read answered: skip the append path's absent-file
|
|
215
|
+
// hydration for the rest of this process.
|
|
216
|
+
hydratedMirrors.add(path);
|
|
217
|
+
}
|
|
218
|
+
catch (error) {
|
|
219
|
+
console.warn(`[agent-serve] memory hydration failed for "${ctx.agentName}" (keeping the existing mirror): ${error instanceof Error ? error.message : String(error)}`);
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
/**
|
|
223
|
+
* Hosted pods carry the pin and a provisioned store by construction (v2
|
|
224
|
+
* hosting binds `factory-api-v1` unconditionally and refuses pre-0.2.1
|
|
225
|
+
* artifacts). Reaching this without them means a misconfigured
|
|
226
|
+
* environment; there is no client-side write to fall back to.
|
|
227
|
+
*/
|
|
228
|
+
const refuseMisconfiguredLane = (agentName, verb) => {
|
|
229
|
+
console.error(`[agent-serve] memory ${verb} for "${agentName}" dropped: the store API lane is unavailable (missing/foreign AGENT_SERVE_STORE_PROTOCOL pin or no provisioned store). This July has no client-side journal fallback; fix the hosting pin.`);
|
|
230
|
+
};
|
|
139
231
|
return {
|
|
232
|
+
prepareSession(ctx) {
|
|
233
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
234
|
+
var _a;
|
|
235
|
+
// Chained on the same per-journal key as appends, so hydration never
|
|
236
|
+
// interleaves with an append's mirror write.
|
|
237
|
+
const key = agentStoreKeys.memoryJournal(ctx.agentName);
|
|
238
|
+
const prior = (_a = appendChains.get(key)) !== null && _a !== void 0 ? _a : Promise.resolve();
|
|
239
|
+
const next = prior
|
|
240
|
+
.catch(() => { })
|
|
241
|
+
.then(() => __awaiter(this, void 0, void 0, function* () {
|
|
242
|
+
if (!isStoreApiLaneEnabled(hosted)) {
|
|
243
|
+
refuseMisconfiguredLane(ctx.agentName, "hydration");
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
yield hydrateMirror(ctx);
|
|
247
|
+
}));
|
|
248
|
+
appendChains.set(key, next);
|
|
249
|
+
yield next;
|
|
250
|
+
});
|
|
251
|
+
},
|
|
140
252
|
appendTurn(record, ctx) {
|
|
141
253
|
return __awaiter(this, void 0, void 0, function* () {
|
|
142
254
|
var _a;
|
|
255
|
+
// Soft-fail by construction (appendViaStoreApi never throws), but
|
|
256
|
+
// still chained per journal key: the local mirror's hydrate-then-
|
|
257
|
+
// append must not interleave with itself. Lane availability is
|
|
258
|
+
// re-resolved lazily per append, so a pin bound after serve start
|
|
259
|
+
// takes effect without a restart.
|
|
143
260
|
const key = agentStoreKeys.memoryJournal(ctx.agentName);
|
|
144
261
|
const prior = (_a = appendChains.get(key)) !== null && _a !== void 0 ? _a : Promise.resolve();
|
|
145
|
-
const next = prior
|
|
262
|
+
const next = prior
|
|
263
|
+
.catch(() => { })
|
|
264
|
+
.then(() => __awaiter(this, void 0, void 0, function* () {
|
|
265
|
+
if (!isStoreApiLaneEnabled(hosted)) {
|
|
266
|
+
refuseMisconfiguredLane(ctx.agentName, "append");
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
yield appendViaStoreApi(record, ctx);
|
|
270
|
+
}));
|
|
146
271
|
appendChains.set(key, next);
|
|
147
272
|
yield next;
|
|
148
273
|
});
|
|
@@ -230,6 +355,24 @@ export function memoryHook(options = {}) {
|
|
|
230
355
|
};
|
|
231
356
|
return defineHook({
|
|
232
357
|
events: {
|
|
358
|
+
"session.started"(_event, ctx) {
|
|
359
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
360
|
+
var _a;
|
|
361
|
+
// Bring the mirror (the workspace symlink read path) up to date
|
|
362
|
+
// before the session's first turn reads it. Backends without a
|
|
363
|
+
// prepareSession (plain files) have nothing to freshen. Soft-fail:
|
|
364
|
+
// hydration is a freshness upgrade, never a turn blocker.
|
|
365
|
+
try {
|
|
366
|
+
yield (_a = backend.prepareSession) === null || _a === void 0 ? void 0 : _a.call(backend, {
|
|
367
|
+
stateRoot: ctx.stateRoot,
|
|
368
|
+
agentName: ctx.agent.name,
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
catch (error) {
|
|
372
|
+
console.warn(`[agent-serve] memory hydration at session start failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
},
|
|
233
376
|
"message.received"(event, ctx) {
|
|
234
377
|
return __awaiter(this, void 0, void 0, function* () {
|
|
235
378
|
pendingMessages.set(pendingKey(ctx, event.turnId), truncate(event.data.text, maxTextLength));
|