feat(coding-agent): added streamed tool intent display and hashline edit operations

- Added streamed tool intent display in working message to show real-time intent tracking during agent execution.
- Changed intent tracing field name from `$intent` to `_intent` across tool schemas and agent core for consistency.
- Added support for file deletion and renaming operations in hashline edit mode.
- Renamed hashline edit operation fields: `set` to `target`/`new_content`, `set_range` to `first`/`last`/`new_content`, `insert` to `inserted_lines`.
This commit is contained in:
can1357
2026-02-19 18:05:35 +01:00
parent a80d00abfe
commit 7f3079bf2f
11 changed files with 258 additions and 111 deletions
+30 -28
View File
@@ -140,8 +140,8 @@ export type HashlineEdit =
const hashlineContentFormat = (kind: string) =>
Type.Union([
Type.Null(),
Type.Array(Type.String(), { minItems: 1, description: `${kind} lines` }),
Type.String({ minLength: 1, description: `${kind} text, \\n delimited if multiple lines` }),
Type.Array(Type.String(), { description: `${kind} lines` }),
Type.String({ description: `${kind} line` }),
]);
function hashlineParseContent(edit: string | string[] | null): string[] {
@@ -153,6 +153,12 @@ function hashlineParseContent(edit: string | string[] | null): string[] {
return lines;
}
function hashlineParseContentString(edit: string | string[] | null): string {
if (edit === null) return "";
if (Array.isArray(edit)) return edit.join("\n");
return edit;
}
const hashlineTargetEditSchema = Type.Object({
target: Type.String({ description: 'Line reference "LINE#ID"' }),
new_content: hashlineContentFormat("Replacement"),
@@ -190,18 +196,19 @@ function hashlineParseRangeEdit(edit: HashlineEditUnion): HashlineEdit | null {
}
const hashlineInsertEditSchema = Type.Object({
before: Type.Optional(Type.String({ minLength: 1, description: 'Insert before this line "LINE#ID"' })),
after: Type.Optional(Type.String({ minLength: 1, description: 'Insert after this line "LINE#ID"' })),
before: Type.Optional(Type.String({ description: 'Insert before this line "LINE#ID"' })),
after: Type.Optional(Type.String({ description: 'Insert after this line "LINE#ID"' })),
inserted_lines: hashlineContentFormat("Inserted"),
});
function hashlineParseInsertEdit(edit: HashlineEditUnion): HashlineEdit | null {
if ("inserted_lines" in edit) {
const { before = "", after = "", inserted_lines } = edit;
return {
insert: {
before: edit.before,
after: edit.after,
body: hashlineParseContent(edit.inserted_lines),
before: before.length > 0 ? before : undefined,
after: after.length > 0 ? after : undefined,
body: hashlineParseContent(inserted_lines),
},
};
}
@@ -216,11 +223,12 @@ const hashlineReplaceTextEditSchema = Type.Object({
function hashlineParseReplaceTextEdit(edit: HashlineEditUnion): HashlineReplaceEdit | null {
if ("old_text" in edit && "new_text" in edit) {
const { old_text, new_text, all } = edit;
return {
replace: {
old_text: edit.old_text,
new_text: hashlineParseContent(edit.new_text).join("\n"),
all: edit.all,
old_text: old_text,
new_text: hashlineParseContentString(new_text),
all: all,
},
};
}
@@ -239,24 +247,18 @@ const hashlineEditItemSchemaWithReplace = Type.Union([
hashlineReplaceTextEditSchema,
]);
const hashlineEditSchema = Type.Object(
{
path: Type.String({ description: "File path (relative or absolute)" }),
edits: Type.Array(hashlineEditItemSchema, { description: "Array of edit operations" }),
delete: Type.Optional(Type.Literal(true, { description: "Delete the file" })),
rename: Type.Optional(Type.String({ description: "New path for move" })),
},
{ additionalProperties: true },
);
const hashlineEditSchemaWithReplace = Type.Object(
{
path: Type.String({ description: "File path (relative or absolute)" }),
edits: Type.Array(hashlineEditItemSchemaWithReplace, { description: "Array of edit operations" }),
delete: Type.Optional(Type.Literal(true, { description: "Delete the file" })),
rename: Type.Optional(Type.String({ description: "New path for move" })),
},
{ additionalProperties: true },
);
const hashlineEditSchema = Type.Object({
path: Type.String({ description: "File path (relative or absolute)" }),
edits: Type.Array(hashlineEditItemSchema, { description: "Array of edit operations" }),
delete: Type.Optional(Type.Literal(true, { description: "Delete the file" })),
rename: Type.Optional(Type.String({ description: "New path for move" })),
});
const hashlineEditSchemaWithReplace = Type.Object({
path: Type.String({ description: "File path (relative or absolute)" }),
edits: Type.Array(hashlineEditItemSchemaWithReplace, { description: "Array of edit operations" }),
delete: Type.Optional(Type.Literal(true, { description: "Delete the file" })),
rename: Type.Optional(Type.String({ description: "New path for move" })),
});
export type HashlineToolEdit = Static<typeof hashlineEditItemSchemaWithReplace>;
export type HashlineParams = Static<typeof hashlineEditSchemaWithReplace>;