@dxos/assistant 0.14.0 → 0.16.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.
- package/dist/lib/ExecutionGraph.mjs.map +1 -1
- package/dist/lib/chunk-Agent.mjs +202 -0
- package/dist/lib/chunk-Agent.mjs.map +1 -0
- package/dist/lib/chunk-AiContext.mjs +462 -0
- package/dist/lib/chunk-AiContext.mjs.map +1 -0
- package/dist/lib/chunk-AiRequest.mjs.map +1 -1
- package/dist/lib/chunk-AiSession.mjs +2 -2
- package/dist/lib/chunk-AiSession.mjs.map +1 -1
- package/dist/lib/chunk-Alarm.mjs +37 -0
- package/dist/lib/chunk-Alarm.mjs.map +1 -0
- package/dist/lib/chunk-Chat.mjs +258 -0
- package/dist/lib/chunk-Chat.mjs.map +1 -0
- package/dist/lib/chunk-Harness.mjs +4 -4
- package/dist/lib/chunk-Harness.mjs.map +1 -1
- package/dist/lib/chunk-SessionLink.mjs +20 -0
- package/dist/lib/chunk-SessionLink.mjs.map +1 -0
- package/dist/lib/chunk-SkillHooks.mjs +47 -0
- package/dist/lib/chunk-SkillHooks.mjs.map +1 -0
- package/dist/lib/extraction.mjs.map +1 -1
- package/dist/lib/index.mjs +6 -6
- package/dist/lib/index.mjs.map +1 -1
- package/dist/lib/request/AiRequest.mjs +1 -2
- package/dist/lib/session/AiContext.mjs +1 -462
- package/dist/lib/session/AiSession.mjs +1 -2
- package/dist/lib/session/Alarm.mjs +1 -37
- package/dist/lib/session/Harness.mjs +1 -2
- package/dist/lib/session/SessionLink.mjs +1 -20
- package/dist/lib/session/SkillHooks.mjs +1 -47
- package/dist/lib/types/Agent.mjs +1 -202
- package/dist/lib/types/Chat.mjs +1 -258
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +23 -23
- package/src/request/AiRequest.test.ts +1 -1
- package/src/types/Agent.ts +1 -1
- package/dist/lib/session/AiContext.mjs.map +0 -1
- package/dist/lib/session/Alarm.mjs.map +0 -1
- package/dist/lib/session/SessionLink.mjs.map +0 -1
- package/dist/lib/session/SkillHooks.mjs.map +0 -1
- package/dist/lib/types/Agent.mjs.map +0 -1
- package/dist/lib/types/Chat.mjs.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/assistant",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "Natural language interface to DXOS",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -82,34 +82,34 @@
|
|
|
82
82
|
"dependencies": {
|
|
83
83
|
"@automerge/automerge": "3.5.0",
|
|
84
84
|
"lodash.defaultsdeep": "^4.6.1",
|
|
85
|
-
"@dxos/ai": "0.
|
|
86
|
-
"@dxos/compute": "0.
|
|
87
|
-
"@dxos/compute-runtime": "0.
|
|
88
|
-
"@dxos/context": "0.
|
|
89
|
-
"@dxos/debug": "0.
|
|
90
|
-
"@dxos/echo": "0.
|
|
91
|
-
"@dxos/echo-client": "0.
|
|
92
|
-
"@dxos/echo-doc": "0.
|
|
93
|
-
"@dxos/echo-protocol": "0.
|
|
94
|
-
"@dxos/effect": "0.
|
|
95
|
-
"@dxos/errors": "0.
|
|
96
|
-
"@dxos/invariant": "0.
|
|
97
|
-
"@dxos/keys": "0.
|
|
98
|
-
"@dxos/log": "0.
|
|
99
|
-
"@dxos/mcp-client": "0.
|
|
100
|
-
"@dxos/node-std": "0.
|
|
101
|
-
"@dxos/protocols": "0.
|
|
102
|
-
"@dxos/schema": "0.
|
|
103
|
-
"@dxos/types": "0.
|
|
104
|
-
"@dxos/util": "0.
|
|
85
|
+
"@dxos/ai": "0.16.0",
|
|
86
|
+
"@dxos/compute": "0.16.0",
|
|
87
|
+
"@dxos/compute-runtime": "0.16.0",
|
|
88
|
+
"@dxos/context": "0.16.0",
|
|
89
|
+
"@dxos/debug": "0.16.0",
|
|
90
|
+
"@dxos/echo": "0.16.0",
|
|
91
|
+
"@dxos/echo-client": "0.16.0",
|
|
92
|
+
"@dxos/echo-doc": "0.16.0",
|
|
93
|
+
"@dxos/echo-protocol": "0.16.0",
|
|
94
|
+
"@dxos/effect": "0.16.0",
|
|
95
|
+
"@dxos/errors": "0.16.0",
|
|
96
|
+
"@dxos/invariant": "0.16.0",
|
|
97
|
+
"@dxos/keys": "0.16.0",
|
|
98
|
+
"@dxos/log": "0.16.0",
|
|
99
|
+
"@dxos/mcp-client": "0.16.0",
|
|
100
|
+
"@dxos/node-std": "0.16.0",
|
|
101
|
+
"@dxos/protocols": "0.16.0",
|
|
102
|
+
"@dxos/schema": "0.16.0",
|
|
103
|
+
"@dxos/types": "0.16.0",
|
|
104
|
+
"@dxos/util": "0.16.0"
|
|
105
105
|
},
|
|
106
106
|
"devDependencies": {
|
|
107
107
|
"@opentelemetry/sdk-trace-base": "^2.11.0",
|
|
108
108
|
"@types/lodash.defaultsdeep": "^4.6.6",
|
|
109
|
-
"effect": "4.0.
|
|
109
|
+
"effect": "4.0.4"
|
|
110
110
|
},
|
|
111
111
|
"peerDependencies": {
|
|
112
|
-
"effect": "4.0.
|
|
112
|
+
"effect": "4.0.4"
|
|
113
113
|
},
|
|
114
114
|
"publishConfig": {
|
|
115
115
|
"access": "public"
|
|
@@ -149,7 +149,7 @@ describe('AiRequest.Request.run (telemetry)', () => {
|
|
|
149
149
|
|
|
150
150
|
const modelSpans = exporter.getFinishedSpans().filter(({ name }) => name.startsWith('LanguageModel.'));
|
|
151
151
|
expect(modelSpans).toHaveLength(2);
|
|
152
|
-
expect(modelSpans.every((span) => span.attributes['gen_ai.
|
|
152
|
+
expect(modelSpans.every((span) => span.attributes['gen_ai.provider.name'] !== undefined)).toEqual(true);
|
|
153
153
|
}).pipe(
|
|
154
154
|
Effect.provide(
|
|
155
155
|
testLayer([{ parts: [toolCall('Echo', { value: 'hello' })] }, { parts: [text('Echoed the value.')] }]),
|
package/src/types/Agent.ts
CHANGED
|
@@ -72,10 +72,10 @@ export class Agent extends Type.makeObject<Agent>(DXN.make('org.dxos.type.agent'
|
|
|
72
72
|
Annotation.FormInlineAnnotation.set(true),
|
|
73
73
|
Schema.annotate({ title: 'Instructions' }),
|
|
74
74
|
),
|
|
75
|
+
// No `UserType`: agents are managed in space settings, not listed with the space's content.
|
|
75
76
|
}).pipe(
|
|
76
77
|
Annotation.LabelAnnotation.set(['name']),
|
|
77
78
|
Annotation.IconAnnotation.set({ icon: 'ph--drone--regular', hue: 'amber' }),
|
|
78
|
-
Annotation.UserType.set(),
|
|
79
79
|
),
|
|
80
80
|
) {}
|
|
81
81
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"AiContext.mjs","names":[],"sources":["../../../src/session/AiContext.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\n// @import-as-namespace\n\nimport * as EArray from 'effect/Array';\nimport * as Context from 'effect/Context';\nimport * as Effect from 'effect/Effect';\nimport * as Function from 'effect/Function';\nimport * as Order from 'effect/Order';\nimport * as Atom from 'effect/reactivity/Atom';\nimport * as AtomRegistry from 'effect/reactivity/AtomRegistry';\nimport * as Schema from 'effect/Schema';\n\nimport * as Skill from '@dxos/compute/Skill';\nimport { Resource } from '@dxos/context';\nimport { Database, DXN, Feed, Obj, Query, type QueryResult, Ref, Type } from '@dxos/echo';\nimport * as AtomEx from '@dxos/effect/AtomEx';\nimport * as RuntimeProvider from '@dxos/effect/RuntimeProvider';\nimport { assertArgument, invariant } from '@dxos/invariant';\nimport { EID, type URI } from '@dxos/keys';\nimport { log } from '@dxos/log';\nimport { ComplexSet, isNonNullable } from '@dxos/util';\n\n/**\n * Thread message that binds or unbinds contextual objects to a conversation.\n */\nexport class Binding extends Type.makeObject<Binding>(DXN.make('org.dxos.type.contextBinding', '0.1.0'))(\n Schema.Struct({\n skills: Schema.Struct({\n added: Schema.Array(Ref.Ref(Skill.Skill)),\n removed: Schema.Array(Ref.Ref(Skill.Skill)),\n }),\n\n objects: Schema.Struct({\n added: Schema.Array(Ref.Ref(Obj.Unknown)),\n removed: Schema.Array(Ref.Ref(Obj.Unknown)),\n }),\n }),\n) {}\nexport type BindingProps = Partial<{\n skills: Ref.Ref<Skill.Skill>[];\n objects: Ref.Ref<Obj.Unknown>[];\n}>;\n\nexport class Bindings {\n readonly skills = new ComplexSet<Ref.Ref<Skill.Skill>>((ref) => ref.uri);\n\n // TODO(burdon): Some DXNs have the Space prefix so only compare the object ID.\n readonly objects = new ComplexSet<Ref.Ref<Obj.Unknown>>((ref) => {\n const echoUri = EID.tryParse(ref.uri);\n return echoUri ? EID.getEntityId(echoUri) : undefined;\n });\n\n toJSON(): { skills: URI.URI[]; objects: URI.URI[] } {\n return {\n skills: EArray.fromIterable(this.skills).map((ref) => ref.uri),\n objects: EArray.fromIterable(this.objects).map((ref) => ref.uri),\n };\n }\n}\n\n/**\n * Bindings appended in this realm, per feed id (stable whether or not the feed is persisted yet).\n *\n * Lets {@link Binder.sync} skip its re-read when nothing here could have changed the bindings: the\n * re-read is a feed-scoped query, which waits for an index pass over every pending write, and it\n * exists only for read-your-writes — a binding written elsewhere arrives through the live query.\n */\nconst bindingWrites = new Map<string, number>();\n\nconst bindingWriteCount = (feed: Feed.Feed): number => bindingWrites.get(feed.id) ?? 0;\n\nconst countBindingWrite = (feed: Feed.Feed): void => {\n bindingWrites.set(feed.id, (bindingWrites.get(feed.id) ?? 0) + 1);\n};\n\nexport type BinderOptions = {\n feed: Feed.Feed;\n runtime: Context.Context<Database.Service>;\n /** @effect/atom-react Registry for reactive state management. */\n registry?: AtomRegistry.AtomRegistry;\n /** Holds bindings in memory until {@link Binder.flush}, so the feed need not be stored yet (a draft conversation). */\n hold?: boolean;\n};\n\n/**\n * Manages bindings of skills and objects to a conversation.\n */\nexport class Binder extends Resource {\n private readonly _skills = Atom.make<Skill.Skill[]>([]).pipe(Atom.keepAlive);\n private readonly _objects = Atom.make<Obj.Unknown[]>([]).pipe(Atom.keepAlive);\n private readonly _registry: AtomRegistry.AtomRegistry;\n private readonly _feed: Feed.Feed;\n private readonly _runtime: Context.Context<Database.Service>;\n private readonly _hold: boolean;\n\n #bindingsQuery: QueryResult.QueryResult<Binding> | undefined;\n\n /** {@link bindingWriteCount} at the last read of the bindings query. */\n #readWrites = 0;\n\n /**\n * Keys of the refs the feed already binds, whether or not their targets resolve here: a registry\n * skill bound by URI never matches its resolved target's URI, so the atoms alone cannot tell it is bound.\n */\n #bound = { skills: new Set<URI.URI>(), objects: new Set<URI.URI>() };\n\n #pending?: Binding[];\n\n /** Bumped by each held write, so only the latest resolution of the held bindings lands. */\n #heldGeneration = 0;\n\n constructor(options: BinderOptions) {\n super();\n assertArgument(options.feed, 'options.feed', 'Feed is required');\n assertArgument(options.runtime, 'options.runtime', 'Feed runtime is required');\n this._feed = options.feed;\n this._runtime = options.runtime;\n this._registry = options.registry ?? AtomEx.makeRegistry();\n this._hold = options.hold ?? false;\n }\n\n /**\n * Returns the skills atom for subscription.\n */\n get skills(): Atom.Atom<Skill.Skill[]> {\n return this._skills;\n }\n\n /**\n * Returns the objects atom for subscription.\n */\n get objects(): Atom.Atom<Obj.Unknown[]> {\n return this._objects;\n }\n\n /**\n * Gets the current skills value.\n */\n getSkills(): Skill.Skill[] {\n return this._registry.get(this._skills);\n }\n\n /**\n * Gets the current objects value.\n */\n getObjects(): Obj.Unknown[] {\n return this._registry.get(this._objects);\n }\n\n /**\n * Subscribe to changes in skills.\n */\n subscribeSkills(cb: (skills: Skill.Skill[]) => void): () => void {\n return this._registry.subscribe(this._skills, () => cb(this._registry.get(this._skills)));\n }\n\n /**\n * Subscribe to changes in objects.\n */\n subscribeObjects(cb: (objects: Obj.Unknown[]) => void): () => void {\n return this._registry.subscribe(this._objects, () => cb(this._registry.get(this._objects)));\n }\n\n protected override async _open(): Promise<void> {\n if (this._hold) {\n this.#pending = [];\n return;\n }\n await this._follow();\n }\n\n /**\n * Writes a holding binder's bindings to its feed, which the caller has stored, as one binding. Later\n * writes go straight to the feed, which the binder does not follow.\n */\n async flush(): Promise<void> {\n const held = this.#pending;\n if (!held) {\n return;\n }\n invariant(Obj.getDatabase(this._feed), 'The feed must be stored before its bindings are flushed.');\n this.#pending = undefined;\n const { skills, objects } = this._reduce(held);\n if (skills.size > 0 || objects.size > 0) {\n await this._append(\n Obj.make(Binding, {\n skills: { added: [...skills], removed: [] },\n objects: { added: [...objects], removed: [] },\n }),\n );\n }\n }\n\n private async _follow(): Promise<void> {\n const bindingsQuery = await RuntimeProvider.runPromise(Effect.succeed(this._runtime))(\n Feed.query(this._feed, Query.type(Binding)),\n );\n this.#bindingsQuery = bindingsQuery;\n\n // Process initial state before returning.\n this.#readWrites = bindingWriteCount(this._feed);\n const initialResults = await bindingsQuery.run();\n await this._updateBindings(initialResults);\n\n // Subscribe to future changes.\n this._ctx.onDispose(\n bindingsQuery.subscribe(async () => {\n await this._updateBindings(bindingsQuery.results);\n }),\n );\n }\n\n /**\n * Re-reads bindings from the feed to pick up changes made by other processes in this realm, such\n * as a tool that bound a skill. A no-op when none has been written since the last read.\n */\n async sync(): Promise<void> {\n const writes = bindingWriteCount(this._feed);\n if (this.#bindingsQuery && writes !== this.#readWrites) {\n let results: Binding[];\n try {\n results = await this.#bindingsQuery.run();\n } catch (error) {\n // The query's live subscription already keeps the bindings current, so a re-read that fails\n // (an index query timing out under load) costs freshness, not correctness — and a caller\n // running this between agent turns would otherwise fail the whole agent process on it.\n log.warn('bindings sync failed; keeping the current bindings', { error });\n return;\n }\n log('sync', { bindingItems: results.length });\n await this._updateBindings(results);\n // Only after the update lands, so one that fails is retried by the next sync.\n this.#readWrites = writes;\n log('sync complete', {\n skills: this._registry.get(this._skills).length,\n // Read the meta key directly: `Skill.getKey` throws on a space-authored skill, which would\n // make a diagnostic log the thing that breaks the sync.\n skillKeys: this._registry.get(this._skills).map((skill) => Obj.getMeta(skill).key),\n });\n }\n }\n\n private async _updateBindings(items: Binding[]): Promise<void> {\n // Skip update if no items - preserve existing state set by bind().\n if (items.length === 0) {\n return;\n }\n\n const bindings = this._reduce(inAppendOrder(items));\n this.#bound = {\n skills: new Set([...bindings.skills].map((ref) => refKey(ref.uri))),\n objects: new Set([...bindings.objects].map((ref) => refKey(ref.uri))),\n };\n\n log('_updateBindings', {\n items: items.length,\n skillRefs: [...bindings.skills].map((ref) => ({ uri: ref.uri, available: ref.isAvailable })),\n });\n\n // Resolve references (loading them first if needed).\n const currentSkills = this._registry.get(this._skills);\n const currentObjects = this._registry.get(this._objects);\n const resolvedSkills = await this._resolve(bindings.skills, currentSkills);\n const resolvedObjects = await this._resolve(bindings.objects, currentObjects);\n\n log('_updateBindings resolved', {\n resolvedSkills: resolvedSkills.length,\n resolvedSkillKeys: resolvedSkills.map((bp) => Obj.getMeta(bp).key ?? '<missing>'),\n });\n\n // Filter current state to only items still in the reduced binding set,\n // then merge in newly resolved items. This ensures unbind events are respected.\n const reducedSkillDxns = new Set<URI.URI>([...bindings.skills].map((ref) => ref.uri));\n const reducedObjectDxns = new Set<URI.URI>([...bindings.objects].map((ref) => ref.uri));\n const filteredSkills = currentSkills.filter((obj) => {\n const uri = Obj.getURI(obj);\n return uri != null && reducedSkillDxns.has(uri);\n });\n const filteredObjects = currentObjects.filter((obj) => {\n const uri = Obj.getURI(obj);\n return uri != null && reducedObjectDxns.has(uri);\n });\n const mergedSkills = this._mergeInto(filteredSkills, resolvedSkills);\n const mergedObjects = this._mergeInto(filteredObjects, resolvedObjects);\n\n this._registry.set(this._skills, mergedSkills);\n this._registry.set(this._objects, mergedObjects);\n\n log('updated bindings', {\n skills: mergedSkills.length,\n objects: mergedObjects.length,\n });\n }\n\n protected override async _close(): Promise<void> {\n // Reset atoms to empty state.\n this._registry.set(this._skills, []);\n this._registry.set(this._objects, []);\n }\n\n async bind({ skills, objects }: BindingProps): Promise<void> {\n const currentSkills = this._registry.get(this._skills);\n const currentObjects = this._registry.get(this._objects);\n\n const { added: addedSkills, next: nextSkills } = this._processBindings(skills, currentSkills, this.#bound.skills);\n const { added: addedObjects, next: nextObjects } = this._processBindings(\n objects,\n currentObjects,\n this.#bound.objects,\n );\n if (!addedSkills.length && !addedObjects.length) {\n return;\n }\n addedSkills.forEach((ref) => this.#bound.skills.add(refKey(ref.uri)));\n addedObjects.forEach((ref) => this.#bound.objects.add(refKey(ref.uri)));\n\n // Atomic updates - subscribers notified automatically.\n this._registry.set(this._skills, nextSkills);\n this._registry.set(this._objects, nextObjects);\n\n log('bind', { skills: addedSkills.length, objects: addedObjects.length });\n await this._write(\n Obj.make(Binding, {\n skills: {\n added: addedSkills,\n removed: [],\n },\n objects: {\n added: addedObjects,\n removed: [],\n },\n }),\n );\n }\n\n async unbind({ skills, objects }: BindingProps): Promise<void> {\n if (!skills?.length && !objects?.length) {\n return;\n }\n\n (skills ?? []).forEach((ref) => this.#bound.skills.delete(refKey(ref.uri)));\n (objects ?? []).forEach((ref) => this.#bound.objects.delete(refKey(ref.uri)));\n\n // Immediately update atom state so removals are reflected before the queue round-trips.\n const removedSkillKeys = new Set((skills ?? []).map((ref) => refKey(ref.uri)));\n const removedObjectKeys = new Set((objects ?? []).map((ref) => refKey(ref.uri)));\n if (removedSkillKeys.size > 0) {\n const current = this._registry.get(this._skills);\n this._registry.set(\n this._skills,\n current.filter((obj) => !removedSkillKeys.has(refKey(Obj.getURI(obj)))),\n );\n }\n if (removedObjectKeys.size > 0) {\n const current = this._registry.get(this._objects);\n this._registry.set(\n this._objects,\n current.filter((obj) => !removedObjectKeys.has(refKey(Obj.getURI(obj)))),\n );\n }\n\n log('unbind', { skills: skills?.length, objects: objects?.length });\n await this._write(\n Obj.make(Binding, {\n skills: {\n added: [],\n removed: skills ?? [],\n },\n objects: {\n added: [],\n removed: objects ?? [],\n },\n }),\n );\n }\n\n private async _write(binding: Binding): Promise<void> {\n if (this.#pending) {\n this.#pending.push(binding);\n await this._resolveHeld(this.#pending);\n return;\n }\n await this._append(binding);\n }\n\n /**\n * Sets the atoms from the held bindings. Their refs have no feed query to hydrate them, so each is\n * resolved against the database, which also spans the registry.\n */\n private async _resolveHeld(held: Binding[]): Promise<void> {\n const generation = ++this.#heldGeneration;\n const { db } = Context.get(this._runtime, Database.Service);\n const { skills, objects } = this._reduce(held);\n const hydrate = <T extends Obj.Unknown>(refs: Iterable<Ref.Ref<T>>): Ref.Ref<T>[] =>\n [...refs].map((ref) => (ref.isAvailable ? ref : db.makeRef<T>(ref.uri)));\n const [resolvedSkills, resolvedObjects] = await Promise.all([\n this._resolve(hydrate(skills), this._registry.get(this._skills)),\n this._resolve(hydrate(objects), this._registry.get(this._objects)),\n ]);\n if (generation !== this.#heldGeneration) {\n return;\n }\n this._registry.set(this._skills, resolvedSkills);\n this._registry.set(this._objects, resolvedObjects);\n }\n\n private async _append(binding: Binding): Promise<void> {\n await RuntimeProvider.runPromise(Effect.succeed(this._runtime))(Feed.append(this._feed, [binding]));\n countBindingWrite(this._feed);\n }\n\n /**\n * Process bindings to filter duplicates (against the resolved targets and the refs already bound) and\n * determine next state.\n */\n private _processBindings<T extends Obj.Unknown>(\n refs: Ref.Ref<T>[] | undefined,\n current: T[],\n bound: ReadonlySet<URI.URI>,\n ): { added: Ref.Ref<T>[]; next: T[] } {\n const next = [...current];\n const added: Ref.Ref<T>[] = [];\n if (!refs?.length) {\n return { added, next };\n }\n\n const seen = new Set<URI.URI>([...bound, ...current.map((obj) => refKey(Obj.getURI(obj)))]);\n for (const ref of refs) {\n const key = refKey(ref.uri);\n if (seen.has(key)) {\n continue;\n }\n seen.add(key);\n added.push(ref);\n\n // Only resolve target if available (has target or resolver).\n if (ref.isAvailable) {\n const target = ref.target;\n if (target) {\n next.push(target);\n }\n }\n }\n\n return { added, next };\n }\n\n /**\n * Reduce results into sets of skills and objects.\n *\n * Order-sensitive: a later removal must fold after the addition it undoes, so callers pass items\n * in append order (see {@link inAppendOrder}).\n */\n private _reduce(items: Binding[]): Bindings {\n return Function.pipe(\n items,\n EArray.reduce(new Bindings(), (context, { skills, objects }) => {\n skills.added.forEach((ref) => context.skills.add(ref));\n skills.removed.forEach((ref) => context.skills.delete(ref));\n\n objects.added.forEach((ref) => context.objects.add(ref));\n objects.removed.forEach((ref) => {\n for (const obj of context.objects) {\n if (\n obj.uri === ref.uri ||\n (EID.tryParse(obj.uri) &&\n EID.tryParse(ref.uri) &&\n EID.getEntityId(EID.tryParse(obj.uri)!) === EID.getEntityId(EID.tryParse(ref.uri)!))\n ) {\n context.objects.delete(obj);\n }\n }\n });\n\n return context;\n }),\n );\n }\n\n /**\n * Merge resolved items into the current set, adding only items not already present (by DXN).\n */\n private _mergeInto<T extends Obj.Unknown>(current: T[], resolved: T[]): T[] {\n const seen = new Set(current.map((obj) => Obj.getURI(obj)));\n const merged = [...current];\n for (const obj of resolved) {\n const uri = Obj.getURI(obj);\n if (!seen.has(uri)) {\n seen.add(uri);\n merged.push(obj);\n }\n }\n return merged;\n }\n\n /**\n * Resolve references to objects, loading them first if needed and falling back to existing objects.\n * DXN refs (e.g. `dxn:org.dxos.skill.database`) resolve via the wired-up ECHO ref resolver\n * which already spans both the space DB and the hypergraph registry.\n */\n private async _resolve<T extends Obj.Unknown>(refs: Iterable<Ref.Ref<T>>, current: T[]): Promise<T[]> {\n const refArray = [...refs];\n\n // Load all refs that need loading.\n await Promise.all(refArray.map((ref) => ref.tryLoad()));\n\n return refArray\n .map((ref) => {\n let target: T | undefined;\n // Only resolve target if available (has target or resolver).\n if (ref.isAvailable) {\n target = ref.target;\n }\n\n // Fallback to existing object.\n const resolved = target ?? current.find((obj) => Obj.getURI(obj) === ref.uri);\n if (!resolved) {\n // A binding that cannot load (e.g. a registry skill the host never registered) would otherwise\n // vanish from the session without trace.\n log.warn('unresolved context binding', { uri: ref.uri });\n }\n return resolved;\n })\n .filter(isNonNullable);\n }\n}\n\n/**\n * Identity of a bound ref: an ECHO URI compares in its local form, since some carry the space and some do not.\n */\nconst refKey = (uri: URI.URI): URI.URI => {\n const echoUri = EID.tryParse(uri);\n return echoUri ? EID.toLocal(echoUri) : uri;\n};\n\n/**\n * Bindings in the order they were appended, which is the order the fold has to see them: a query\n * returns an unordered set, so an unsorted fold can apply a removal before the addition it undoes\n * and silently keep the object bound. Server-assigned position is authoritative; a locally-written\n * block has none yet and sorts last, which is correct — it is the newest.\n */\nconst inAppendOrder = (items: readonly Binding[]): Binding[] =>\n EArray.sort(items, Order.mapInput(Order.Number, Feed.getPosition));\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Alarm.mjs","names":[],"sources":["../../../src/session/Alarm.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// @import-as-namespace\n\nimport * as Schema from 'effect/Schema';\n\nimport { DXN, Obj, Type } from '@dxos/echo';\n\n/**\n * Feed-level record scheduling a future self-wake of the agent.\n * Managed with regular feed CRUD: append schedules, `Feed.remove` cancels a pending alarm. When it\n * fires, the agent appends the wake-up `Message` carrying `SessionStore.AckAnnotation` naming this\n * record — the ack filters it out of the pending set; the record itself stays in the feed.\n */\nexport class Alarm extends Type.makeObject<Alarm>(DXN.make('org.dxos.type.alarm', '0.1.0'))(\n Schema.Struct({\n /** Epoch milliseconds at which the agent should wake. */\n wakeAt: Schema.Number,\n /** Reminder surfaced to the agent when the alarm fires. */\n message: Schema.optional(Schema.String),\n /** ISO timestamp when the alarm was scheduled. */\n created: Schema.String,\n }),\n) {}\n\n/**\n * Most alarms that may wake the agent in a row without a user prompt between them; each wake is a full turn over the\n * whole context, so an agent polling on alarms would otherwise spend without bound.\n */\nexport const MAX_SELF_WAKES = 10;\n\nexport type MakeProps = {\n wakeAt: number;\n message?: string;\n created?: string;\n};\n\nexport const make = ({ wakeAt, message, created }: MakeProps): Alarm =>\n Obj.make(Alarm, {\n wakeAt,\n message,\n created: created ?? new Date().toISOString(),\n });\n"],"mappings":";;;;;;;;;;;;;;;AAgBA,IAAa,QAAb,cAA2B,KAAK,WAAkB,IAAI,KAAK,uBAAuB,OAAO,CAAC,CAAC,CACzF,OAAO,OAAO;;CAEZ,QAAQ,OAAO;;CAEf,SAAS,OAAO,SAAS,OAAO,MAAM;;CAEtC,SAAS,OAAO;AAClB,CAAC,CACH,CAAC,CAAC,CAAC;;;;;AAMH,IAAa,iBAAiB;AAQ9B,IAAa,QAAQ,EAAE,QAAQ,SAAS,cACtC,IAAI,KAAK,OAAO;CACd;CACA;CACA,SAAS,4BAAW,IAAI,KAAK,EAAA,CAAE,YAAY;AAC7C,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SessionLink.mjs","names":[],"sources":["../../../src/session/SessionLink.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\n// @import-as-namespace\n\nimport * as Schema from 'effect/Schema';\n\nimport { DXN, Feed, Obj, Ref, Type } from '@dxos/echo';\n\n/**\n * Feed-level record that links this session to a point in another session's history.\n * When present in a feed, the messages from the referenced feed up to and including\n * `messageId` are prepended to the conversation history before each turn.\n */\nexport class SessionLink extends Type.makeObject<SessionLink>(DXN.make('org.dxos.type.sessionLink', '0.1.0'))(\n Schema.Struct({\n /** Reference to the feed of the source session. */\n feedRef: Ref.Ref(Feed.Feed),\n /** Messages from the source feed up to and including this message ID are injected. */\n messageId: Obj.ID,\n }),\n) {}\n"],"mappings":";;;;;;;;;;AAeA,IAAa,cAAb,cAAiC,KAAK,WAAwB,IAAI,KAAK,6BAA6B,OAAO,CAAC,CAAC,CAC3G,OAAO,OAAO;;CAEZ,SAAS,IAAI,IAAI,KAAK,IAAI;;CAE1B,WAAW,IAAI;AACjB,CAAC,CACH,CAAC,CAAC,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SkillHooks.mjs","names":[],"sources":["../../../src/session/SkillHooks.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// @import-as-namespace\n\nimport * as Effect from 'effect/Effect';\n\nimport * as Operation from '@dxos/compute/Operation';\nimport * as Skill from '@dxos/compute/Skill';\nimport { Database, Obj } from '@dxos/echo';\nimport { invariant } from '@dxos/invariant';\nimport { log } from '@dxos/log';\n\n/**\n * Tag of the lifecycle point a hook fires at, matching {@link Skill.HookSpec}.\n */\nexport type HookPhase = 'begin-request' | 'end-request';\n\n/**\n * Invokes a resolved operation with the hook's templated input. Begin and end hooks fire in\n * different contexts (the agent's turn fiber vs. a child process with Tier B reachable), so the\n * invocation strategy is supplied by the caller rather than fixed here. `R` carries the invoker's\n * own requirements (e.g. `Operation.Service`) up into {@link runHooks}.\n */\nexport type HookInvoker<R> = (\n operation: Operation.Definition.Any,\n input: Record<string, unknown>,\n hook: Skill.Hook,\n) => Effect.Effect<void, never, R>;\n\n/**\n * Runs every {@link Skill.Hook} on `skills` whose spec matches `phase`. Each hook resolves its\n * `function` ref to a {@link Operation.PersistentOperation}, deserializes it to a definition, and\n * invokes it with the templated `input` via `invoke`. Hooks without a function ref are skipped.\n *\n * Hook failures are isolated: a throwing hook logs and is swallowed so one skill's hook cannot\n * abort the request lifecycle (or the sibling hooks).\n */\nexport const runHooks = <R>({\n skills,\n phase,\n invoke,\n}: {\n skills: readonly Skill.Skill[];\n phase: HookPhase;\n invoke: HookInvoker<R>;\n}): Effect.Effect<void, never, Database.Service | R> =>\n Effect.gen(function* () {\n for (const skill of skills) {\n for (const hook of skill.hooks ?? []) {\n if (hook.spec._tag !== phase) {\n continue;\n }\n if (!hook.function) {\n continue;\n }\n\n yield* Effect.gen(function* () {\n const record = yield* Database.load(hook.function!);\n invariant(Obj.instanceOf(Operation.PersistentOperation, record), 'Hook function must be an operation.');\n const operation = Operation.deserialize(record);\n // Hooks carry no event payload (the spec is a bare tag), so the input template is passed\n // through verbatim — the hook's operation reads any conversation state it needs itself.\n yield* invoke(operation, { ...hook.input }, hook);\n }).pipe(\n Effect.catchCause((cause) =>\n // Meta key rather than `Skill.getKey`: a space-authored skill has none, and an error\n // report must not itself throw.\n Effect.sync(() => log.warn('skill hook failed', { phase, skill: Obj.getMeta(skill).key, cause })),\n ),\n );\n }\n }\n });\n"],"mappings":";;;;;;;;;;;;;;;;;AAuCA,IAAa,YAAe,EAC1B,QACA,OACA,aAMA,OAAO,IAAI,aAAa;CACtB,KAAK,MAAM,SAAS,QAClB,KAAK,MAAM,QAAQ,MAAM,SAAS,CAAC,GAAG;EACpC,IAAI,KAAK,KAAK,SAAS,OACrB;EAEF,IAAI,CAAC,KAAK,UACR;EAGF,OAAO,OAAO,IAAI,aAAa;GAC7B,MAAM,SAAS,OAAO,SAAS,KAAK,KAAK,QAAS;GAClD,UAAU,IAAI,WAAW,UAAU,qBAAqB,MAAM,GAAG,uCAAoC;IAAA,YAAA;IAAA,GAAA;IAAA,GAAA;IAAA,GAAA;IAAA,GAAA,CAAA,yDAAA,uCAAA;GAAA,CAAC;GAItG,OAAO,OAHW,UAAU,YAAY,MAG1B,GAAW,EAAE,GAAG,KAAK,MAAM,GAAG,IAAI;EAClD,CAAC,CAAC,CAAC,KACD,OAAO,YAAY,UAGjB,OAAO,WAAW,IAAI,KAAK,qBAAqB;GAAE;GAAO,OAAO,IAAI,QAAQ,KAAK,CAAC,CAAC;GAAK;EAAM,GAAA;GAAA,YAAA;GAAA,GAAA;GAAA,GAAA;GAAA,GAAA;EAAA,CAAC,CAAC,CAClG,CACF;CACF;AAEJ,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Agent.mjs","names":[],"sources":["../../../src/types/Agent.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// @import-as-namespace\n\nimport * as Effect from 'effect/Effect';\nimport * as Schema from 'effect/Schema';\n\nimport type * as AgentService from '@dxos/compute/AgentService';\nimport * as Instructions from '@dxos/compute/Instructions';\nimport * as Skill from '@dxos/compute/Skill';\nimport { Annotation, Database, DXN, type Error as EchoError, Feed, Filter, Obj, Ref, Type } from '@dxos/echo';\nimport * as EffectEx from '@dxos/effect/EffectEx';\nimport { IdentityDid } from '@dxos/keys';\n\nimport type * as Harness from '../session/Harness.ts';\nimport { HarnessContextError } from '../util/errors.ts';\nimport * as Chat from './Chat.ts';\n\n/**\n * An agent identity: a personality (attribution DID) plus its preset payload (instructions with\n * text, skills, objects, and commands). Owns no conversation state — a chat is linked to the agent\n * it runs as by the ECHO parent edge (the agent parents its chats), and durable work products live on a Project\n * (plugin-projects DESIGN.md, \"Agent ↔ Project convergence\").\n */\n\n/**\n * The AI session runtime (MCP SDK, Anthropic client, ~280 KB) is loaded lazily: this module holds\n * the Agent *schema*, which core plugins reference for operation definitions, so the runtime loads\n * only when an agent operation actually runs.\n */\nconst aiContextRuntime = () => import('../session/AiContext.ts');\nconst harnessRuntime = () => import('../session/Harness.ts');\n\nexport class Agent extends Type.makeObject<Agent>(DXN.make('org.dxos.type.agent', '0.2.0'))(\n Schema.Struct({\n name: Schema.optional(Schema.String),\n\n /**\n * Stable identity DID for the agent, used to attribute content it authors (e.g. suggestion\n * branches) as its own author — distinct from any human or other agent. Provisioned\n * externally, never minted by {@link makeInitialized} (see the note there); the slot a real\n * HALO identity DID takes once agents get first-class identities. Optional because nothing\n * populates it yet.\n */\n did: Schema.optional(\n // Annotated inside `optional`: the form reads the title from the value schema, not the wrapper.\n IdentityDid.annotate({\n title: 'DID',\n description: \"The agent's identity DID; attributes content the agent authors.\",\n }),\n ).annotate({\n title: 'DID',\n description: \"The agent's DID.\",\n }),\n\n /**\n * Master switch for the agent's automation (propagated onto its compiled routine triggers).\n */\n enabled: Schema.optional(Schema.Boolean).annotate({\n title: 'Enabled',\n description: 'Master switch for agent automation; propagated to all triggers on sync.',\n }),\n\n /**\n * Instructions for the agent — the preset payload (text, skills, objects, commands) a chat\n * receives when the agent is applied to it. Owned: `SetParent` cascades it with the agent.\n */\n instructions: Ref.Ref(Instructions.Instructions).pipe(\n Annotation.SetParent.set(),\n Annotation.FormInlineAnnotation.set(true),\n Schema.annotate({ title: 'Instructions' }),\n ),\n }).pipe(\n Annotation.LabelAnnotation.set(['name']),\n Annotation.IconAnnotation.set({ icon: 'ph--drone--regular', hue: 'amber' }),\n Annotation.UserType.set(),\n ),\n) {}\n\n/**\n * Resolves the agent's instructions and their markdown text.\n */\nexport const loadInstructions = (\n agent: Agent,\n): Effect.Effect<\n { text: string; instructions: Instructions.Instructions },\n EchoError.EntityNotFoundError,\n Database.Service\n> =>\n Effect.gen(function* () {\n const instructions = yield* Database.load(agent.instructions);\n const text = yield* Database.load(instructions.text).pipe(\n Effect.map((doc) => doc.content),\n Effect.catchTag('EntityNotFoundError', () => Effect.succeed('')),\n );\n return { text, instructions };\n });\n\n/**\n * Resolves the agent's primary chat (the agent holds no chat ref): the latest chat parented to the\n * agent. Entity ids are ULIDs, so the id order is creation order — `resetChatHistory` makes the\n * replacement chat primary simply by creating it later.\n */\nexport const loadChat = (agent: Agent): Effect.Effect<Chat.Chat | undefined, never, Database.Service> =>\n Effect.gen(function* () {\n // A child-of filter rather than a `.children()` traversal: EDGE's query planner has no hierarchy\n // traversal, so an agent hosted there could not resolve its chat.\n const chats = yield* Database.query(Filter.and(Filter.type(Chat.Chat), Filter.childOf(agent))).run;\n return (\n chats\n // Chats bridged from an external conversation (a Discord thread) carry its foreign key; they are\n // the agent's too, but never its own primary chat.\n .filter((chat) => Obj.getMeta(chat).keys.length === 0)\n .sort((left, right) => left.id.localeCompare(right.id))\n .at(-1)\n );\n }).pipe(Effect.orDie);\n\n/**\n * Resolves the agent a chat runs as, if any. Plain (agentless) chats yield `undefined`.\n * The parent is loaded with the object, so this is synchronous — no query.\n */\nexport const loadForChat = (chat: Chat.Chat): Effect.Effect<Agent | undefined> =>\n Effect.sync(() => {\n const parent = Obj.getParent(chat);\n return parent && Obj.instanceOf(Agent, parent) ? parent : undefined;\n });\n\n/**\n * Where a chat's turns run: as its `remote` flag says, else on EDGE for an agent's chat, since its chats share\n * the agent's one brain, which only EDGE holds. An explicit `remote: false` keeps an agent's chats local, for\n * a runtime with no EDGE to reach (a story or test), where every chat shares the client's brain instead.\n */\nexport const chatLocation = (chat: Chat.Chat): AgentService.AgentLocation =>\n (chat.remote ?? isAgentChat(chat)) ? 'edge' : 'local';\n\n/** Whether the chat runs as an agent (the agent parents it); synchronous, like {@link loadForChat}. */\nexport const isAgentChat = (chat: Chat.Chat): boolean => {\n const parent = Obj.getParent(chat);\n return parent !== undefined && Obj.instanceOf(Agent, parent);\n};\n\nexport type MakeProps = Omit<Obj.MakeProps<typeof Agent>, 'instructions'> & {\n instructions: string;\n skills?: Ref.Ref<Skill.Skill>[];\n contextObjects?: Ref.Ref<Obj.Any>[];\n};\n\n/**\n * Creates a fully initialized Agent with its first chat and context bindings.\n *\n * @param props - Agent properties including spec, skills, and context objects.\n * @param skill - The skill to use for the agent context: a skill object is cloned into the space, a ref\n * (e.g. a registry URI) is bound as-is so the agent follows the compiled skill until customized.\n * @returns An Effect that yields the initialized Agent.\n */\nexport const makeInitialized = (\n props: MakeProps,\n // TODO(burdon): Reconcile with props.skills.\n skill: Skill.Skill | Ref.Ref<Skill.Skill>,\n): Effect.Effect<Agent, never, Database.Service> =>\n Effect.gen(function* () {\n const { skills: propsSkills, contextObjects, ...agentProps } = props;\n\n // Loaded before anything is persisted: a rejected chunk after the first `Database.add` would\n // leave a half-built agent graph behind with nothing to clean it up.\n const AiContextRuntime = yield* Effect.promise(aiContextRuntime);\n\n // Persist any inline (transient) skills so their refs are resolvable from feed bindings later.\n // Refs created with Ref.make(obj) carry an inline target, but when stored in ECHO and read back\n // by a new AiSession, the target is lost and must be found in the DB via tryLoad().\n // `peek` rather than `target`: a registry-URI ref has no inline target and no resolver yet.\n const persistedPropsSkills = yield* Effect.all(\n (propsSkills ?? []).map((ref) => {\n const target = ref.peek();\n return target !== undefined\n ? Database.add(target).pipe(Effect.map((persisted) => Ref.make(persisted)))\n : Effect.succeed(ref);\n }),\n );\n\n // The typed Instructions is the agent's preset payload: text plus skill set.\n const instructions = yield* Database.add(\n Instructions.make({ text: props.instructions, skills: persistedPropsSkills }),\n );\n const agent = yield* Database.add(\n Obj.make(Agent, {\n // `did` (if provided) flows through via agentProps. Not auto-minted here: `IdentityDid.random()`\n // uses uncontrolled `randomBytes`, which would make agent creation non-deterministic and break\n // memoized-LLM tests. Minting is deferred to the runtime-identity provision (see agent-identity\n // spec), where it can be deterministic or a real HALO DID.\n ...agentProps,\n instructions: Ref.make(instructions),\n enabled: props.enabled ?? true,\n }),\n );\n const feed = yield* Database.add(Feed.make());\n const runtime = yield* Effect.context<Database.Service>();\n const contextBinder = yield* EffectEx.acquireReleaseResource(() => new AiContextRuntime.Binder({ feed, runtime }));\n const agentSkill = Ref.isRef(skill) ? skill : Ref.make(yield* Database.add(Obj.clone(skill, { deep: 'all' })));\n\n const chat = yield* Database.add(\n Chat.make({\n feed: Ref.make(feed),\n // Steered through the chat's own channel: instructions render into the system prompt.\n // Identity/attribution comes from the companion link (ref on the agent + parent edge).\n instructions: Ref.make(instructions),\n }),\n );\n Chat.linkCompanion({ chat, subject: agent });\n yield* Effect.promise(() =>\n contextBinder.bind({\n skills: [agentSkill, ...persistedPropsSkills],\n objects: [Ref.make(agent), Ref.make(chat), ...(contextObjects ?? [])],\n }),\n );\n return agent;\n }).pipe(Effect.scoped);\n\n/**\n * Resets the agent's chat history by rebuilding the chat context.\n * Preserves the existing skills and objects from the current chat context.\n *\n * @param agent - The agent whose chat history should be reset. Must have an existing chat.\n * @returns An Effect that resets the chat history.\n */\nexport const resetChatHistory = (agent: Agent): Effect.Effect<void, EchoError.EntityNotFoundError, Database.Service> =>\n Effect.gen(function* () {\n const existingChat = yield* loadChat(agent);\n if (!existingChat) {\n return yield* Effect.die(new Error('Agent must have an existing chat to reset.'));\n }\n\n const existingFeed = yield* Database.load(existingChat.feed);\n const runtime = yield* Effect.context<Database.Service>();\n const AiContextRuntime = yield* Effect.promise(aiContextRuntime);\n const existingContextBinder = yield* EffectEx.acquireReleaseResource(\n () =>\n new AiContextRuntime.Binder({\n feed: existingFeed,\n runtime,\n }),\n );\n const skills = existingContextBinder.getSkills().map(Skill.makeRef);\n const objects = existingContextBinder\n .getObjects()\n .filter((object) => !Obj.instanceOf(Chat.Chat, object))\n .map((object) => Ref.make(object));\n\n const feed = yield* Database.add(Feed.make());\n const contextBinder = yield* EffectEx.acquireReleaseResource(() => new AiContextRuntime.Binder({ feed, runtime }));\n\n const chat = yield* Database.add(\n Chat.make({\n feed: Ref.make(feed),\n instructions: agent.instructions,\n }),\n );\n Chat.linkCompanion({ chat, subject: agent });\n yield* Effect.promise(() =>\n contextBinder.bind({\n skills,\n objects: [...objects, Ref.make(chat)],\n }),\n );\n\n // The old chat stays parented (history is retired, not deleted); the new chat is primary\n // because `loadChat` resolves the latest child by creation order.\n }).pipe(Effect.scoped);\n\nexport const getFromChatContext: Effect.Effect<\n Agent,\n HarnessContextError | Harness.NotSupportedError,\n Harness.HarnessService\n> = Effect.gen(function* () {\n const HarnessRuntime = yield* Effect.promise(harnessRuntime);\n const agents = yield* HarnessRuntime.queryContext(Filter.type(Agent));\n if (agents.length !== 1) {\n return yield* Effect.fail(new HarnessContextError({ type: 'agent', count: agents.length }));\n }\n\n const agent = agents[0];\n return agent;\n});\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Chat.mjs","names":[],"sources":["../../../src/types/Chat.ts"],"sourcesContent":["//\n// Copyright 2024 DXOS.org\n//\n\n// @import-as-namespace\n\nimport * as Cause from 'effect/Cause';\nimport * as Effect from 'effect/Effect';\nimport * as Option from 'effect/Option';\nimport * as Schema from 'effect/Schema';\n\nimport { SessionConfig } from '@dxos/ai';\nimport * as Instructions from '@dxos/compute/Instructions';\nimport * as Project from '@dxos/compute/Project';\nimport { Annotation, Database, DXN, Feed, Filter, Obj, Ref, Type } from '@dxos/echo';\nimport { log } from '@dxos/log';\nimport { ArchivableAnnotation } from '@dxos/schema';\nimport { Task } from '@dxos/types';\n\n/**\n * AI chat session.\n */\n// TODO(burdon): Rename to Session?\nexport class Chat extends Type.makeObject<Chat>(DXN.make('org.dxos.type.assistant.chat', '0.2.0'))(\n Schema.Struct({\n name: Schema.String.pipe(Schema.optional),\n viewType: Schema.String.pipe(Schema.optional),\n\n /**\n * Runs this conversation's agent on the edge rather than locally, mirroring a trigger's own\n * `remote` flag. When unset, the agent runs locally on the client.\n */\n remote: Schema.Boolean.pipe(Schema.annotate({ title: 'Remote' }), Schema.optional),\n\n /** Message feed, owned by the chat so `SetParent` cascades it. */\n feed: Ref.Ref(Feed.Feed).pipe(Annotation.SetParent.set(), Annotation.FormInputAnnotation.set(false)),\n\n /**\n * Instructions steering this conversation, rendered into the system prompt at request time.\n * Held by reference (never copied), so a project's chats follow edits to its instructions.\n */\n instructions: Schema.optional(Ref.Ref(Instructions.Instructions).pipe(Annotation.FormInputAnnotation.set(false))),\n\n /**\n * How this conversation runs (its model), chosen in the chat rather than globally so it survives\n * a remount and travels with the chat. Unset fields fall back to the project's, then the agent's.\n */\n session: Schema.optional(SessionConfig.SessionConfig.pipe(Annotation.FormInputAnnotation.set(false))),\n\n /**\n * The working checklist, flat and ordered. Deliberately NOT an owning (`SetParent`) field: a\n * chat may work on a task that belongs somewhere else — a project's task set delegates one here\n * — and an owning field re-parents every resolved member on each update of the chat, which\n * would silently move that task out of the set that owns it. Tasks the chat itself creates are\n * parented to it explicitly; see {@link addTask}.\n */\n tasks: Schema.Array(Ref.Ref(Task.Task)).pipe(Annotation.FormInputAnnotation.set(false)),\n }).pipe(\n Annotation.LabelAnnotation.set(['name']),\n Annotation.IconAnnotation.set({\n icon: 'ph--sparkle--regular',\n hue: 'amber',\n }),\n Annotation.UserType.set(),\n ArchivableAnnotation.set(true),\n ),\n) {}\n\n/** Module-level alias so callers importing the namespace avoid the doubled `Chat.Chat.fields`. */\nexport const fields = Chat.fields;\n\nexport const make = (\n props: Omit<Obj.MakeProps<typeof Chat>, 'tasks'> & { tasks?: ReadonlyArray<Ref.Ref<Task.Task>> },\n): Chat => Obj.make(Chat, { ...props, tasks: props.tasks ?? [] });\n\n/**\n * Refs to the chats accompanying an object, stored on the subject itself (replaces the former\n * `CompanionTo` relation): the annotation is deleted with the subject, and its refs make the\n * parented chats real children — referenced and cascaded — rather than ref-less parent-edge\n * orphans reachable only by index query.\n */\nexport const CompanionChatAnnotation = Annotation.make({\n id: 'org.dxos.assistant.companionChats',\n schema: Schema.Array(Ref.Ref(Chat)),\n});\n\n/**\n * Links a chat to the subject it accompanies (a Project, an Agent, a document, ...): a ref on the\n * subject via {@link CompanionChatAnnotation} plus the ECHO parent edge. Idempotent per chat.\n */\nexport const linkCompanion = ({ chat, subject }: { chat: Chat; subject: Obj.Unknown }): void => {\n const existing = Annotation.get(subject, CompanionChatAnnotation);\n const chats = existing.pipe(Option.getOrElse((): readonly Ref.Ref<Chat>[] => []));\n if (!chats.some((ref) => ref.uri === Ref.make(chat).uri)) {\n if (Option.isNone(existing)) {\n Obj.update(subject, (subject) => {\n Annotation.set(subject, CompanionChatAnnotation, [Ref.make(chat)]);\n });\n } else {\n // Splice in place so only this ref is appended; Annotation.update validates the result.\n Annotation.update(subject, CompanionChatAnnotation, (chats) => {\n chats.push(Ref.make(chat));\n });\n }\n }\n Obj.setParent(chat, subject);\n};\n\n/**\n * Starts a chat on a default session config — a project's, say — copied rather than referenced, so\n * a model later picked in the chat is the chat's own. A chat already carrying a config keeps it.\n */\nexport const seedSession = (chat: Chat, session: SessionConfig.SessionConfig | undefined): void => {\n if (!session || chat.session) {\n return;\n }\n\n Obj.update(chat, (chat) => {\n chat.session = { ...session };\n });\n};\n\n/** Creates a task the chat owns and appends it to the checklist. */\nexport const addTask = (\n db: Database.Database,\n chat: Chat,\n title: string,\n props: Partial<Omit<Obj.MakeProps<typeof Task.Task>, 'title'>> = {},\n): Task.Task => {\n // Ownership is decided at creation rather than by membership, so a task the chat made cascades\n // with it while a delegated one keeps the parent it arrived with.\n const task = db.add(Task.make({ title: title.trim(), status: 'todo', ...props, [Obj.Parent]: chat }));\n Obj.update(chat, (chat) => {\n chat.tasks.push(Ref.make(task));\n });\n return task;\n};\n\n/**\n * Appends existing tasks to the checklist. Ownership is deliberately untouched — the task keeps the\n * parent it arrived with (contrast {@link addTask}, which parents what the chat creates), so a task\n * borrowed from a project's set stays in that set. Refs already on the checklist are skipped.\n * Returns the refs actually appended.\n */\nexport const assignTasks = (chat: Chat, tasks: readonly Ref.Ref<Task.Task>[]): Ref.Ref<Task.Task>[] => {\n const added: Ref.Ref<Task.Task>[] = [];\n Obj.update(chat, (chat) => {\n // Matched on entity id rather than target, so an unloaded ref still de-duplicates.\n const present = new Set(chat.tasks.map((ref) => Task.refEntityId(ref)).filter((id) => id !== undefined));\n for (const ref of tasks) {\n const id = Task.refEntityId(ref);\n if (id === undefined || present.has(id)) {\n continue;\n }\n present.add(id);\n added.push(ref);\n }\n chat.tasks.push(...added);\n });\n return added;\n};\n\n/**\n * Takes tasks off the checklist without destroying them — the inverse of {@link assignTasks}, and\n * distinct from {@link deleteTask}, which also removes the members the chat owns. Returns the refs\n * actually removed.\n */\nexport const unassignTasks = (chat: Chat, tasks: readonly Ref.Ref<Task.Task>[]): Ref.Ref<Task.Task>[] => {\n const ids = new Set(tasks.map((ref) => Task.refEntityId(ref)).filter((id) => id !== undefined));\n const removed = chat.tasks.filter((ref) => {\n const id = Task.refEntityId(ref);\n return id !== undefined && ids.has(id);\n });\n if (removed.length > 0) {\n Obj.update(chat, (chat) => {\n chat.tasks = chat.tasks.filter((ref) => {\n const id = Task.refEntityId(ref);\n return id === undefined || !ids.has(id);\n });\n });\n }\n return [...removed];\n};\n\n/**\n * Remove a task and its sub-tasks from `tasks`, the chat's checklist loaded in full (see\n * {@link loadTasks}) — an unloaded child is invisible to the walk and would be left orphaned in\n * the array. Returns everything dropped from the checklist.\n *\n * Only members the chat owns are destroyed: a delegated task belongs to the set that parents it,\n * so taking it off this checklist must not delete it from there.\n */\nexport const deleteTask = (\n db: Database.Database,\n chat: Chat,\n tasks: readonly Task.Task[],\n task: Task.Task,\n): Task.Task[] => {\n const subtree = Task.subtree(tasks, task);\n const ids = new Set(subtree.map((member) => member.id));\n Obj.update(chat, (chat) => {\n // Matched on the ref's own entity id rather than its target, so an entry whose object is not\n // loaded is still swept.\n chat.tasks = chat.tasks.filter((ref) => {\n const id = Task.refEntityId(ref);\n return id === undefined || !ids.has(id);\n });\n });\n for (const member of subtree) {\n if (Obj.getParent(member)?.id === chat.id) {\n db.remove(member);\n }\n }\n return subtree;\n};\n\n/** The chat's feed entity id, readable without resolving the ref. */\nexport const feedEntityId = (chat: Chat): string | undefined => Task.refEntityId(chat.feed);\n\n/**\n * The chat that owns `feed`. The chat owns its feed (`SetParent`), so the parent edge answers this\n * without a query; the scan is the fallback for a feed whose parent was never stamped.\n */\nexport const loadForFeed = (feed: Feed.Feed): Effect.Effect<Chat | undefined, never, Database.Service> =>\n Effect.gen(function* () {\n const parent = Obj.getParent(feed);\n if (parent && Obj.instanceOf(Chat, parent)) {\n return parent;\n }\n const chats = yield* Database.query(Filter.type(Chat)).run;\n return chats.find((chat) => feedEntityId(chat) === feed.id);\n // A chat-less feed is legitimate (a bare `AiSession`, or a database with the type unregistered),\n // so callers get `undefined` rather than a failure — but a query that actually broke is logged,\n // since it is otherwise indistinguishable from the feed simply having no chat.\n }).pipe(\n Effect.catchCause((cause) =>\n Effect.sync(() => {\n log.warn('chat lookup failed; treating feed as chat-less', { feed: feed.id, cause: Cause.pretty(cause) });\n return undefined;\n }),\n ),\n );\n\n/** Bound on the parent walk below; a conversation sits one or two edges under its project. */\nconst MAX_OWNER_DEPTH = 8;\n\n/**\n * The project a conversation belongs to, if any.\n *\n * Walks the parent chain rather than reading the immediate parent, because a chat reaches its project\n * through whatever owns it — directly for a project chat, through the agent for an agent's chat.\n */\nexport const peekProject = (chat: Chat): Project.Project | undefined => {\n let owner: Obj.Unknown | undefined = Obj.getParent(chat);\n for (let depth = 0; owner && depth < MAX_OWNER_DEPTH; depth++) {\n if (Obj.instanceOf(Project.Project, owner)) {\n return owner;\n }\n owner = Obj.getParent(owner);\n }\n return undefined;\n};\n\n/** Loads the checklist in order, de-duplicated: a concurrent merge can land the same ref twice. */\nexport const loadTasks = (chat: Chat): Effect.Effect<Task.Task[], never, Database.Service> =>\n Effect.gen(function* () {\n const tasks = yield* Effect.forEach(chat.tasks, (task) =>\n Database.load(task).pipe(Effect.orElseSucceed(() => undefined)),\n );\n\n return Task.dedupeById(tasks);\n });\n\n/** Sync twin of {@link loadTasks}; an unresolved ref contributes nothing rather than throwing. */\nexport const resolveTasks = (chat: Chat): Task.Task[] =>\n Task.dedupeById(chat.tasks.filter((ref) => ref.isAvailable).map((ref) => ref.target));\n\n/** A task is open until it reaches a terminal status. */\nexport const isOpenTask = (task: Task.Task): boolean => (task.status ?? 'todo') === 'todo' || task.status === 'started';\n\n/**\n * The conversation's tasks rendered as a numbered checklist (the format the planning prompts\n * speak), or a placeholder when none exist. Ordinals match the task list UI, and non-default\n * status/dependencies are noted so the model can reason about readiness.\n */\nexport const formatChecklist = (chat: Chat): Effect.Effect<string, never, Database.Service> =>\n Effect.gen(function* () {\n const tasks = yield* loadTasks(chat);\n if (tasks.length === 0) {\n return 'No checklist found.';\n }\n\n return formatTasks(tasks);\n });\n\n/**\n * Renders tasks as `1. [ ] Title` lines, ordinals in checklist order, each followed by an indented\n * note line carrying the task's ref and any status/dependency notes — appended to the title, models\n * paste the notes back into it. The ref renders as `[MNEMONIC](uri)` so the mnemonic the user reads\n * and the handle the tools take travel together and get pasted back verbatim.\n */\nconst formatTasks = (tasks: readonly Task.Task[]): string => {\n const ordinals = new Map(tasks.map((task, index) => [task.id, index + 1]));\n return tasks\n .map((task, index) => {\n const line = `${index + 1}. [${task.status === 'done' ? 'x' : ' '}] ${task.title}`;\n // The ref is the handle update-tasks takes, so every line carries one the model can pass back.\n const notes: string[] = [`ref: [${Obj.getMnemonic(task)}](${Obj.getURI(task)})`];\n if (task.status && task.status !== 'todo' && task.status !== 'done') {\n notes.push(task.status);\n }\n\n const deps = (task.dependsOn ?? [])\n .map((ref) => ref.target)\n .filter((target) => target !== undefined)\n .map((target) => ordinals.get(target.id) ?? target.title);\n if (deps.length > 0) {\n notes.push(`depends on ${deps.join(', ')}`);\n }\n\n return `${line}\\n (${notes.join('; ')})`;\n })\n .join('\\n');\n};\n"],"mappings":"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"}
|